blob: ce6e4f8cd0aba7647650e8d6c15e39811188378c [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"
cristye85d0f72013-11-27 02:25:43 +000068#include "MagickCore/random_.h"
69#include "MagickCore/random-private.h"
cristy4c08aed2011-07-01 19:47:50 +000070#include "MagickCore/registry.h"
cristyf034abb2013-11-24 14:16:14 +000071#include "MagickCore/resize.h"
72#include "MagickCore/resize-private.h"
cristy4c08aed2011-07-01 19:47:50 +000073#include "MagickCore/semaphore.h"
74#include "MagickCore/splay-tree.h"
75#include "MagickCore/statistic.h"
76#include "MagickCore/string_.h"
77#include "MagickCore/string-private.h"
78#include "MagickCore/token.h"
cristyf034abb2013-11-24 14:16:14 +000079
80#ifdef MAGICKCORE_CLPERFMARKER
81#include "CLPerfMarker.h"
82#endif
83
cristye85d0f72013-11-27 02:25:43 +000084#define MAGICK_MAX(x,y) (((x) >= (y))?(x):(y))
85#define MAGICK_MIN(x,y) (((x) <= (y))?(x):(y))
86
cristyf034abb2013-11-24 14:16:14 +000087#if defined(MAGICKCORE_OPENCL_SUPPORT)
88
89#define ALIGNED(pointer,type) ((((long)(pointer)) & (sizeof(type)-1)) == 0)
90/*#define ALIGNED(pointer,type) (0) */
91
cristy0c832c62014-03-07 22:21:04 +000092/* pad the global workgroup size to the next multiple of
93 the local workgroup size */
94inline static unsigned int
95 padGlobalWorkgroupSizeToLocalWorkgroupSize(const unsigned int orgGlobalSize,
96 const unsigned int localGroupSize)
97{
98 return ((orgGlobalSize+(localGroupSize-1))/localGroupSize*localGroupSize);
99}
100
cristyf034abb2013-11-24 14:16:14 +0000101static MagickBooleanType checkOpenCLEnvironment(ExceptionInfo* exception)
102{
103 MagickBooleanType flag;
104
105 MagickCLEnv clEnv;
106 clEnv = GetDefaultOpenCLEnv();
cristya22457d2013-12-07 14:03:06 +0000107
cristyf034abb2013-11-24 14:16:14 +0000108 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
109 , sizeof(MagickBooleanType), &flag, exception);
cristycd8b3312013-12-22 01:51:11 +0000110 if (flag != MagickFalse)
cristyf034abb2013-11-24 14:16:14 +0000111 return MagickFalse;
112
113 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED
114 , sizeof(MagickBooleanType), &flag, exception);
115 if (flag == MagickFalse)
116 {
117 if(InitOpenCLEnv(clEnv, exception) == MagickFalse)
118 return MagickFalse;
cristya22457d2013-12-07 14:03:06 +0000119
120 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
121 , sizeof(MagickBooleanType), &flag, exception);
cristycd8b3312013-12-22 01:51:11 +0000122 if (flag != MagickFalse)
cristya22457d2013-12-07 14:03:06 +0000123 return MagickFalse;
cristyf034abb2013-11-24 14:16:14 +0000124 }
125
126 return MagickTrue;
127}
128
129
dirk5dcb7622013-12-01 10:43:43 +0000130static MagickBooleanType checkAccelerateCondition(const Image* image, const ChannelType channel)
cristyf034abb2013-11-24 14:16:14 +0000131{
132 /* check if the image's colorspace is supported */
133 if (image->colorspace != RGBColorspace
cristy0c832c62014-03-07 22:21:04 +0000134 && image->colorspace != sRGBColorspace
135 && image->colorspace != GRAYColorspace)
cristyf034abb2013-11-24 14:16:14 +0000136 return MagickFalse;
137
138 /* check if the channel is supported */
139 if (((channel&RedChannel) == 0)
140 || ((channel&GreenChannel) == 0)
141 || ((channel&BlueChannel) == 0))
142 {
143 return MagickFalse;
144 }
145
146
147 /* check if if the virtual pixel method is compatible with the OpenCL implementation */
148 if ((GetImageVirtualPixelMethod(image) != UndefinedVirtualPixelMethod)&&
149 (GetImageVirtualPixelMethod(image) != EdgeVirtualPixelMethod))
150 return MagickFalse;
151
152 return MagickTrue;
153}
154
cristy0c832c62014-03-07 22:21:04 +0000155static MagickBooleanType checkHistogramCondition(Image *image, const ChannelType channel)
156{
157
158 /* ensure this is the only pass get in for now. */
159 if ((channel & SyncChannels) == 0)
160 return MagickFalse;
161
162 if (image->intensity == Rec601LuminancePixelIntensityMethod ||
163 image->intensity == Rec709LuminancePixelIntensityMethod)
164 return MagickFalse;
165
166 if (image->colorspace != sRGBColorspace)
167 return MagickFalse;
168
169 return MagickTrue;
170}
171
cristyf034abb2013-11-24 14:16:14 +0000172
173static Image* ComputeConvolveImage(const Image* inputImage, const ChannelType channel, const KernelInfo *kernel, ExceptionInfo *exception)
174{
175 MagickBooleanType outputReady;
176 MagickCLEnv clEnv;
177
178 cl_int clStatus;
cristy0c832c62014-03-07 22:21:04 +0000179 size_t global_work_size[3];
180 size_t localGroupSize[3];
cristyf034abb2013-11-24 14:16:14 +0000181 size_t localMemoryRequirement;
182 Image* filteredImage;
183 MagickSizeType length;
184 const void *inputPixels;
185 void *filteredPixels;
186 cl_mem_flags mem_flags;
187 float* kernelBufferPtr;
188 unsigned kernelSize;
189 unsigned int i;
190 void *hostPtr;
cristy0c832c62014-03-07 22:21:04 +0000191 unsigned int matte,
192 filterWidth, filterHeight,
193 imageWidth, imageHeight;
cristyf034abb2013-11-24 14:16:14 +0000194
195 cl_context context;
196 cl_kernel clkernel;
197 cl_mem inputImageBuffer, filteredImageBuffer, convolutionKernel;
198 cl_ulong deviceLocalMemorySize;
cristyf034abb2013-11-24 14:16:14 +0000199
200 cl_command_queue queue;
201
202 /* intialize all CL objects to NULL */
203 context = NULL;
204 inputImageBuffer = NULL;
205 filteredImageBuffer = NULL;
206 convolutionKernel = NULL;
207 clkernel = NULL;
208 queue = NULL;
cristyf034abb2013-11-24 14:16:14 +0000209
210 filteredImage = NULL;
211 outputReady = MagickFalse;
212
213 clEnv = GetDefaultOpenCLEnv();
214 context = GetOpenCLContext(clEnv);
215
216 inputPixels = NULL;
217 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
218 if (inputPixels == (const void *) NULL)
219 {
cristya22457d2013-12-07 14:03:06 +0000220 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
cristyf034abb2013-11-24 14:16:14 +0000221 goto cleanup;
222 }
223
224 /* Create and initialize OpenCL buffers. */
225
226 /* If the host pointer is aligned to the size of CLPixelPacket,
227 then use the host buffer directly from the GPU; otherwise,
228 create a buffer on the GPU and copy the data over */
229 if (ALIGNED(inputPixels,CLPixelPacket))
230 {
231 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
232 }
233 else
234 {
235 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
236 }
237 /* create a CL buffer from image pixel buffer */
238 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +0000239 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000240 if (clStatus != CL_SUCCESS)
241 {
cristy0c832c62014-03-07 22:21:04 +0000242 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000243 goto cleanup;
244 }
245
246 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
247 assert(filteredImage != NULL);
cristy0c832c62014-03-07 22:21:04 +0000248 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +0000249 {
cristya22457d2013-12-07 14:03:06 +0000250 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000251 goto cleanup;
252 }
253 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
254 if (filteredPixels == (void *) NULL)
255 {
cristya22457d2013-12-07 14:03:06 +0000256 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +0000257 goto cleanup;
258 }
259
260 if (ALIGNED(filteredPixels,CLPixelPacket))
261 {
262 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
263 hostPtr = filteredPixels;
264 }
265 else
266 {
267 mem_flags = CL_MEM_WRITE_ONLY;
268 hostPtr = NULL;
269 }
270 /* create a CL buffer from image pixel buffer */
271 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +0000272 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000273 if (clStatus != CL_SUCCESS)
274 {
cristy0c832c62014-03-07 22:21:04 +0000275 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000276 goto cleanup;
277 }
278
279 kernelSize = kernel->width * kernel->height;
cristy0c832c62014-03-07 22:21:04 +0000280 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 +0000281 if (clStatus != CL_SUCCESS)
282 {
cristy0c832c62014-03-07 22:21:04 +0000283 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000284 goto cleanup;
285 }
286
287 queue = AcquireOpenCLCommandQueue(clEnv);
288
cristy0c832c62014-03-07 22:21:04 +0000289 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, convolutionKernel, CL_TRUE, CL_MAP_WRITE, 0, kernelSize * sizeof(float)
cristyf034abb2013-11-24 14:16:14 +0000290 , 0, NULL, NULL, &clStatus);
291 if (clStatus != CL_SUCCESS)
292 {
cristy0c832c62014-03-07 22:21:04 +0000293 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000294 goto cleanup;
295 }
296 for (i = 0; i < kernelSize; i++)
297 {
298 kernelBufferPtr[i] = (float) kernel->values[i];
299 }
cristy0c832c62014-03-07 22:21:04 +0000300 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, convolutionKernel, kernelBufferPtr, 0, NULL, NULL);
301 if (clStatus != CL_SUCCESS)
cristyf034abb2013-11-24 14:16:14 +0000302 {
cristy0c832c62014-03-07 22:21:04 +0000303 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000304 goto cleanup;
305 }
cristy0c832c62014-03-07 22:21:04 +0000306 clEnv->library->clFlush(queue);
307
308 deviceLocalMemorySize = GetOpenCLDeviceLocalMemorySize(clEnv);
cristyf034abb2013-11-24 14:16:14 +0000309
310 /* Compute the local memory requirement for a 16x16 workgroup.
311 If it's larger than 16k, reduce the workgroup size to 8x8 */
312 localGroupSize[0] = 16;
313 localGroupSize[1] = 16;
314 localMemoryRequirement = (localGroupSize[0]+kernel->width-1) * (localGroupSize[1]+kernel->height-1) * sizeof(CLPixelPacket)
315 + kernel->width*kernel->height*sizeof(float);
cristy0c832c62014-03-07 22:21:04 +0000316
317 if (localMemoryRequirement > deviceLocalMemorySize)
cristyf034abb2013-11-24 14:16:14 +0000318 {
cristyf034abb2013-11-24 14:16:14 +0000319 localGroupSize[0] = 8;
320 localGroupSize[1] = 8;
cristyf034abb2013-11-24 14:16:14 +0000321 localMemoryRequirement = (localGroupSize[0]+kernel->width-1) * (localGroupSize[1]+kernel->height-1) * sizeof(CLPixelPacket)
322 + kernel->width*kernel->height*sizeof(float);
323 }
cristyf034abb2013-11-24 14:16:14 +0000324 if (localMemoryRequirement <= deviceLocalMemorySize)
325 {
326 /* get the OpenCL kernel */
cristya22457d2013-12-07 14:03:06 +0000327 clkernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ConvolveOptimized");
cristyf034abb2013-11-24 14:16:14 +0000328 if (clkernel == NULL)
329 {
cristya22457d2013-12-07 14:03:06 +0000330 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000331 goto cleanup;
332 }
333
334 /* set the kernel arguments */
335 i = 0;
cristy0c832c62014-03-07 22:21:04 +0000336 clStatus =clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
337 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
cristyf034abb2013-11-24 14:16:14 +0000338 imageWidth = inputImage->columns;
339 imageHeight = inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +0000340 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageWidth);
341 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageHeight);
342 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&convolutionKernel);
cristyf034abb2013-11-24 14:16:14 +0000343 filterWidth = kernel->width;
344 filterHeight = kernel->height;
cristy0c832c62014-03-07 22:21:04 +0000345 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterWidth);
346 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterHeight);
347 matte = (inputImage->matte==MagickTrue)?1:0;
348 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&matte);
349 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(ChannelType),(void *)&channel);
350 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++, (localGroupSize[0] + kernel->width-1)*(localGroupSize[1] + kernel->height-1)*sizeof(CLPixelPacket),NULL);
351 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++, kernel->width*kernel->height*sizeof(float),NULL);
cristyf034abb2013-11-24 14:16:14 +0000352 if (clStatus != CL_SUCCESS)
353 {
cristy0c832c62014-03-07 22:21:04 +0000354 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000355 goto cleanup;
356 }
357
358 /* pad the global size to a multiple of the local work size dimension */
359 global_work_size[0] = ((inputImage->columns + localGroupSize[0] - 1)/localGroupSize[0] ) * localGroupSize[0] ;
360 global_work_size[1] = ((inputImage->rows + localGroupSize[1] - 1)/localGroupSize[1]) * localGroupSize[1];
361
362 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +0000363 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, clkernel, 2, NULL, global_work_size, localGroupSize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +0000364 if (clStatus != CL_SUCCESS)
365 {
cristy0c832c62014-03-07 22:21:04 +0000366 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000367 goto cleanup;
368 }
369 }
370 else
371 {
372 /* get the OpenCL kernel */
373 clkernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Convolve");
374 if (clkernel == NULL)
375 {
cristya22457d2013-12-07 14:03:06 +0000376 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000377 goto cleanup;
378 }
379
380 /* set the kernel arguments */
381 i = 0;
cristy0c832c62014-03-07 22:21:04 +0000382 clStatus =clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
383 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
384 imageWidth = inputImage->columns;
385 imageHeight = inputImage->rows;
386 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageWidth);
387 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageHeight);
388 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&convolutionKernel);
cristyf034abb2013-11-24 14:16:14 +0000389 filterWidth = kernel->width;
390 filterHeight = kernel->height;
cristy0c832c62014-03-07 22:21:04 +0000391 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterWidth);
392 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterHeight);
393 matte = (inputImage->matte==MagickTrue)?1:0;
394 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&matte);
395 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(ChannelType),(void *)&channel);
cristyf034abb2013-11-24 14:16:14 +0000396 if (clStatus != CL_SUCCESS)
397 {
cristy0c832c62014-03-07 22:21:04 +0000398 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000399 goto cleanup;
400 }
401
cristy0c832c62014-03-07 22:21:04 +0000402 localGroupSize[0] = 8;
403 localGroupSize[1] = 8;
404 global_work_size[0] = (inputImage->columns + (localGroupSize[0]-1))/localGroupSize[0] * localGroupSize[0];
405 global_work_size[1] = (inputImage->rows + (localGroupSize[1]-1))/localGroupSize[1] * localGroupSize[1];
406 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, clkernel, 2, NULL, global_work_size, localGroupSize, 0, NULL, NULL);
407
cristyf034abb2013-11-24 14:16:14 +0000408 if (clStatus != CL_SUCCESS)
409 {
cristy0c832c62014-03-07 22:21:04 +0000410 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000411 goto cleanup;
412 }
413 }
cristy0c832c62014-03-07 22:21:04 +0000414 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +0000415
416 if (ALIGNED(filteredPixels,CLPixelPacket))
417 {
418 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +0000419 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 +0000420 }
421 else
422 {
423 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +0000424 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +0000425 }
426 if (clStatus != CL_SUCCESS)
427 {
cristya22457d2013-12-07 14:03:06 +0000428 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000429 goto cleanup;
430 }
431
432 /* everything is fine! :) */
433 outputReady = MagickTrue;
434
cristyf034abb2013-11-24 14:16:14 +0000435cleanup:
cristya22457d2013-12-07 14:03:06 +0000436 OpenCLLogException(__FUNCTION__,__LINE__,exception);
cristyf034abb2013-11-24 14:16:14 +0000437
438 if (inputImageBuffer != NULL)
cristy0c832c62014-03-07 22:21:04 +0000439 clEnv->library->clReleaseMemObject(inputImageBuffer);
cristyf034abb2013-11-24 14:16:14 +0000440
441 if (filteredImageBuffer != NULL)
cristy0c832c62014-03-07 22:21:04 +0000442 clEnv->library->clReleaseMemObject(filteredImageBuffer);
cristyf034abb2013-11-24 14:16:14 +0000443
444 if (convolutionKernel != NULL)
cristy0c832c62014-03-07 22:21:04 +0000445 clEnv->library->clReleaseMemObject(convolutionKernel);
cristyf034abb2013-11-24 14:16:14 +0000446
447 if (clkernel != NULL)
448 RelinquishOpenCLKernel(clEnv, clkernel);
449
450 if (queue != NULL)
451 RelinquishOpenCLCommandQueue(clEnv, queue);
452
453 if (outputReady == MagickFalse)
454 {
455 if (filteredImage != NULL)
456 {
457 DestroyImage(filteredImage);
458 filteredImage = NULL;
459 }
460 }
461
462 return filteredImage;
463}
464
cristy3f6d1482010-01-20 21:01:21 +0000465/*
466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
467% %
468% %
469% %
cristyf034abb2013-11-24 14:16:14 +0000470% C o n v o l v e I m a g e w i t h O p e n C L %
cristy3f6d1482010-01-20 21:01:21 +0000471% %
472% %
473% %
474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
475%
cristyf034abb2013-11-24 14:16:14 +0000476% ConvolveImage() applies a custom convolution kernel to the image.
cristy3f6d1482010-01-20 21:01:21 +0000477%
cristyf034abb2013-11-24 14:16:14 +0000478% The format of the ConvolveImage method is:
cristy3f6d1482010-01-20 21:01:21 +0000479%
cristyf034abb2013-11-24 14:16:14 +0000480% Image *ConvolveImage(const Image *image,const size_t order,
481% const double *kernel,ExceptionInfo *exception)
482% Image *ConvolveImageChannel(const Image *image,const ChannelType channel,
483% const size_t order,const double *kernel,ExceptionInfo *exception)
484%
485% A description of each parameter follows:
486%
487% o image: the image.
488%
489% o channel: the channel type.
490%
491% o kernel: kernel info.
492%
493% o exception: return any errors or warnings in this structure.
494%
495*/
496
497MagickExport Image* AccelerateConvolveImageChannel(const Image *image, const ChannelType channel, const KernelInfo *kernel, ExceptionInfo *exception)
498{
499 MagickBooleanType status;
500 Image* filteredImage = NULL;
501
502 assert(image != NULL);
503 assert(kernel != (KernelInfo *) NULL);
504 assert(exception != (ExceptionInfo *) NULL);
505
506 status = checkOpenCLEnvironment(exception);
507 if (status == MagickFalse)
508 return NULL;
509
dirk5dcb7622013-12-01 10:43:43 +0000510 status = checkAccelerateCondition(image, channel);
cristyf034abb2013-11-24 14:16:14 +0000511 if (status == MagickFalse)
512 return NULL;
513
514 filteredImage = ComputeConvolveImage(image, channel, kernel, exception);
cristyf034abb2013-11-24 14:16:14 +0000515 return filteredImage;
516}
517
518static MagickBooleanType ComputeFunctionImage(Image *image, const ChannelType channel,const MagickFunction function,
519 const size_t number_parameters,const double *parameters, ExceptionInfo *exception)
520{
521 MagickBooleanType status;
522
523 MagickCLEnv clEnv;
524
525 MagickSizeType length;
526 void* pixels;
527 float* parametersBufferPtr;
528
529 cl_int clStatus;
530 cl_context context;
531 cl_kernel clkernel;
532 cl_command_queue queue;
533 cl_mem_flags mem_flags;
534 cl_mem imageBuffer;
535 cl_mem parametersBuffer;
536 size_t globalWorkSize[2];
537
538 unsigned int i;
539
540 status = MagickFalse;
541
542 context = NULL;
543 clkernel = NULL;
544 queue = NULL;
545 imageBuffer = NULL;
546 parametersBuffer = NULL;
547
548 clEnv = GetDefaultOpenCLEnv();
549 context = GetOpenCLContext(clEnv);
550
551 pixels = GetPixelCachePixels(image, &length, exception);
552 if (pixels == (void *) NULL)
553 {
cristya22457d2013-12-07 14:03:06 +0000554 (void) OpenCLThrowMagickException(exception, GetMagickModule(), CacheWarning,
cristyf034abb2013-11-24 14:16:14 +0000555 "GetPixelCachePixels failed.",
556 "'%s'", image->filename);
557 goto cleanup;
558 }
559
560
561 if (ALIGNED(pixels,CLPixelPacket))
562 {
563 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
564 }
565 else
566 {
567 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
568 }
569 /* create a CL buffer from image pixel buffer */
570 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +0000571 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)pixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000572 if (clStatus != CL_SUCCESS)
573 {
cristy0c832c62014-03-07 22:21:04 +0000574 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000575 goto cleanup;
576 }
577
cristy0c832c62014-03-07 22:21:04 +0000578 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 +0000579 if (clStatus != CL_SUCCESS)
580 {
cristy0c832c62014-03-07 22:21:04 +0000581 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000582 goto cleanup;
583 }
584
585 queue = AcquireOpenCLCommandQueue(clEnv);
586
cristy0c832c62014-03-07 22:21:04 +0000587 parametersBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, parametersBuffer, CL_TRUE, CL_MAP_WRITE, 0, number_parameters * sizeof(float)
cristyf034abb2013-11-24 14:16:14 +0000588 , 0, NULL, NULL, &clStatus);
589 if (clStatus != CL_SUCCESS)
590 {
cristy0c832c62014-03-07 22:21:04 +0000591 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000592 goto cleanup;
593 }
594 for (i = 0; i < number_parameters; i++)
595 {
596 parametersBufferPtr[i] = (float)parameters[i];
597 }
cristy0c832c62014-03-07 22:21:04 +0000598 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, parametersBuffer, parametersBufferPtr, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +0000599 if (clStatus != CL_SUCCESS)
600 {
cristy0c832c62014-03-07 22:21:04 +0000601 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000602 goto cleanup;
603 }
cristy0c832c62014-03-07 22:21:04 +0000604 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +0000605
606 clkernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "FunctionImage");
607 if (clkernel == NULL)
608 {
cristya22457d2013-12-07 14:03:06 +0000609 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000610 goto cleanup;
611 }
612
613 /* set the kernel arguments */
614 i = 0;
cristy0c832c62014-03-07 22:21:04 +0000615 clStatus =clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
616 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(ChannelType),(void *)&channel);
617 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(MagickFunction),(void *)&function);
618 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&number_parameters);
619 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&parametersBuffer);
cristyf034abb2013-11-24 14:16:14 +0000620 if (clStatus != CL_SUCCESS)
621 {
cristy0c832c62014-03-07 22:21:04 +0000622 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000623 goto cleanup;
624 }
625
626 globalWorkSize[0] = image->columns;
627 globalWorkSize[1] = image->rows;
628 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +0000629 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, clkernel, 2, NULL, globalWorkSize, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +0000630 if (clStatus != CL_SUCCESS)
631 {
cristy0c832c62014-03-07 22:21:04 +0000632 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000633 goto cleanup;
634 }
cristy0c832c62014-03-07 22:21:04 +0000635 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +0000636
637
638 if (ALIGNED(pixels,CLPixelPacket))
639 {
640 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +0000641 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 +0000642 }
643 else
644 {
645 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +0000646 clStatus = clEnv->library->clEnqueueReadBuffer(queue, imageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), pixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +0000647 }
648 if (clStatus != CL_SUCCESS)
649 {
cristya22457d2013-12-07 14:03:06 +0000650 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000651 goto cleanup;
652 }
653 status = MagickTrue;
654
655cleanup:
cristya22457d2013-12-07 14:03:06 +0000656 OpenCLLogException(__FUNCTION__,__LINE__,exception);
cristyf034abb2013-11-24 14:16:14 +0000657
658 if (clkernel != NULL) RelinquishOpenCLKernel(clEnv, clkernel);
659 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
cristy0c832c62014-03-07 22:21:04 +0000660 if (imageBuffer != NULL) clEnv->library->clReleaseMemObject(imageBuffer);
661 if (parametersBuffer != NULL) clEnv->library->clReleaseMemObject(parametersBuffer);
cristyf034abb2013-11-24 14:16:14 +0000662
663 return status;
664}
665
666
667
668MagickExport MagickBooleanType
669 AccelerateFunctionImage(Image *image, const ChannelType channel,const MagickFunction function,
670 const size_t number_parameters,const double *parameters, ExceptionInfo *exception)
671{
672 MagickBooleanType status;
673
674 status = MagickFalse;
675
676 assert(image != NULL);
677 assert(exception != (ExceptionInfo *) NULL);
678
679 status = checkOpenCLEnvironment(exception);
cristycd8b3312013-12-22 01:51:11 +0000680 if (status != MagickFalse)
cristyf034abb2013-11-24 14:16:14 +0000681 {
dirk5dcb7622013-12-01 10:43:43 +0000682 status = checkAccelerateCondition(image, channel);
cristycd8b3312013-12-22 01:51:11 +0000683 if (status != MagickFalse)
cristyf034abb2013-11-24 14:16:14 +0000684 {
685 status = ComputeFunctionImage(image, channel, function, number_parameters, parameters, exception);
cristyf034abb2013-11-24 14:16:14 +0000686 }
687 }
688 return status;
689}
690
691
692static MagickBooleanType splitImage(const Image* inputImage)
693{
694 MagickBooleanType split;
695
696 MagickCLEnv clEnv;
697 unsigned long allocSize;
698 unsigned long tempSize;
699
700 clEnv = GetDefaultOpenCLEnv();
701
702 allocSize = GetOpenCLDeviceMaxMemAllocSize(clEnv);
703 tempSize = inputImage->columns * inputImage->rows * 4 * 4;
704
705 /*
706 printf("alloc size: %lu\n", allocSize);
707 printf("temp size: %lu\n", tempSize);
708 */
709
710 split = ((tempSize > allocSize) ? MagickTrue:MagickFalse);
711
712 return split;
713}
714
715static Image* ComputeBlurImage(const Image* inputImage, const ChannelType channel, const double radius, const double sigma, ExceptionInfo *exception)
716{
717 MagickBooleanType outputReady;
718 Image* filteredImage;
719 MagickCLEnv clEnv;
720
721 cl_int clStatus;
722
723 const void *inputPixels;
724 void *filteredPixels;
725 cl_mem_flags mem_flags;
726
727 cl_context context;
728 cl_mem inputImageBuffer, tempImageBuffer, filteredImageBuffer, imageKernelBuffer;
729 cl_kernel blurRowKernel, blurColumnKernel;
730 cl_command_queue queue;
731
732 void* hostPtr;
733 float* kernelBufferPtr;
734 MagickSizeType length;
735
736 char geometry[MaxTextExtent];
737 KernelInfo* kernel = NULL;
738 unsigned int kernelWidth;
739 unsigned int imageColumns, imageRows;
740
741 unsigned int i;
742
743 context = NULL;
744 filteredImage = NULL;
745 inputImageBuffer = NULL;
746 tempImageBuffer = NULL;
747 filteredImageBuffer = NULL;
748 imageKernelBuffer = NULL;
749 blurRowKernel = NULL;
750 blurColumnKernel = NULL;
751 queue = NULL;
752
753 outputReady = MagickFalse;
754
755 clEnv = GetDefaultOpenCLEnv();
756 context = GetOpenCLContext(clEnv);
757 queue = AcquireOpenCLCommandQueue(clEnv);
758
759 /* Create and initialize OpenCL buffers. */
760 {
761 inputPixels = NULL;
762 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
763 if (inputPixels == (const void *) NULL)
764 {
cristya22457d2013-12-07 14:03:06 +0000765 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
cristyf034abb2013-11-24 14:16:14 +0000766 goto cleanup;
767 }
768 /* If the host pointer is aligned to the size of CLPixelPacket,
769 then use the host buffer directly from the GPU; otherwise,
770 create a buffer on the GPU and copy the data over */
771 if (ALIGNED(inputPixels,CLPixelPacket))
772 {
773 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
774 }
775 else
776 {
777 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
778 }
779 /* create a CL buffer from image pixel buffer */
780 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +0000781 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000782 if (clStatus != CL_SUCCESS)
783 {
cristy0c832c62014-03-07 22:21:04 +0000784 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000785 goto cleanup;
786 }
787 }
788
789 /* create output */
790 {
791 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
792 assert(filteredImage != NULL);
cristy0c832c62014-03-07 22:21:04 +0000793 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +0000794 {
cristya22457d2013-12-07 14:03:06 +0000795 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000796 goto cleanup;
797 }
798 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
799 if (filteredPixels == (void *) NULL)
800 {
cristya22457d2013-12-07 14:03:06 +0000801 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +0000802 goto cleanup;
803 }
804
805 if (ALIGNED(filteredPixels,CLPixelPacket))
806 {
807 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
808 hostPtr = filteredPixels;
809 }
810 else
811 {
812 mem_flags = CL_MEM_WRITE_ONLY;
813 hostPtr = NULL;
814 }
815 /* create a CL buffer from image pixel buffer */
816 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +0000817 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000818 if (clStatus != CL_SUCCESS)
819 {
cristy0c832c62014-03-07 22:21:04 +0000820 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000821 goto cleanup;
822 }
823 }
824
825 /* create processing kernel */
826 {
827 (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
828 kernel=AcquireKernelInfo(geometry);
829 if (kernel == (KernelInfo *) NULL)
830 {
cristya22457d2013-12-07 14:03:06 +0000831 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "MemoryAllocationFailed.",".");
cristyf034abb2013-11-24 14:16:14 +0000832 goto cleanup;
833 }
834
cristy0c832c62014-03-07 22:21:04 +0000835 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 +0000836 if (clStatus != CL_SUCCESS)
837 {
cristy0c832c62014-03-07 22:21:04 +0000838 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000839 goto cleanup;
840 }
cristy0c832c62014-03-07 22:21:04 +0000841 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 +0000842 if (clStatus != CL_SUCCESS)
843 {
cristy0c832c62014-03-07 22:21:04 +0000844 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000845 goto cleanup;
846 }
847
848 for (i = 0; i < kernel->width; i++)
849 {
850 kernelBufferPtr[i] = (float) kernel->values[i];
851 }
852
cristy0c832c62014-03-07 22:21:04 +0000853 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +0000854 if (clStatus != CL_SUCCESS)
855 {
cristy0c832c62014-03-07 22:21:04 +0000856 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000857 goto cleanup;
858 }
859 }
860
861 {
862
863 /* create temp buffer */
864 {
865 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +0000866 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000867 if (clStatus != CL_SUCCESS)
868 {
cristy0c832c62014-03-07 22:21:04 +0000869 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000870 goto cleanup;
871 }
872 }
873
874 /* get the OpenCL kernels */
875 {
876 blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRow");
877 if (blurRowKernel == NULL)
878 {
cristya22457d2013-12-07 14:03:06 +0000879 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000880 goto cleanup;
881 };
882
883 blurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurColumn");
884 if (blurColumnKernel == NULL)
885 {
cristya22457d2013-12-07 14:03:06 +0000886 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000887 goto cleanup;
888 };
889 }
890
891 {
892 /* need logic to decide this value */
893 int chunkSize = 256;
894
895 {
896 imageColumns = inputImage->columns;
897 imageRows = inputImage->rows;
898
899 /* set the kernel arguments */
900 i = 0;
cristy0c832c62014-03-07 22:21:04 +0000901 clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
902 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
903 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel);
904 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
cristyf034abb2013-11-24 14:16:14 +0000905 kernelWidth = kernel->width;
cristy0c832c62014-03-07 22:21:04 +0000906 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
907 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
908 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows);
909 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL);
cristyf034abb2013-11-24 14:16:14 +0000910 if (clStatus != CL_SUCCESS)
911 {
cristy0c832c62014-03-07 22:21:04 +0000912 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000913 goto cleanup;
914 }
915 }
916
917 /* launch the kernel */
918 {
919 size_t gsize[2];
920 size_t wsize[2];
921
922 gsize[0] = chunkSize*((inputImage->columns+chunkSize-1)/chunkSize);
923 gsize[1] = inputImage->rows;
924 wsize[0] = chunkSize;
925 wsize[1] = 1;
926
cristy0c832c62014-03-07 22:21:04 +0000927 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +0000928 if (clStatus != CL_SUCCESS)
929 {
cristy0c832c62014-03-07 22:21:04 +0000930 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000931 goto cleanup;
932 }
cristy0c832c62014-03-07 22:21:04 +0000933 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +0000934 }
935 }
936
937 {
938 /* need logic to decide this value */
939 int chunkSize = 256;
940
941 {
942 imageColumns = inputImage->columns;
943 imageRows = inputImage->rows;
944
945 /* set the kernel arguments */
946 i = 0;
cristy0c832c62014-03-07 22:21:04 +0000947 clStatus=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
948 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
949 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(ChannelType),&channel);
950 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
cristyf034abb2013-11-24 14:16:14 +0000951 kernelWidth = kernel->width;
cristy0c832c62014-03-07 22:21:04 +0000952 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
953 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
954 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows);
955 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_float4)*(chunkSize+kernel->width),(void *)NULL);
cristyf034abb2013-11-24 14:16:14 +0000956 if (clStatus != CL_SUCCESS)
957 {
cristy0c832c62014-03-07 22:21:04 +0000958 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000959 goto cleanup;
960 }
961 }
962
963 /* launch the kernel */
964 {
965 size_t gsize[2];
966 size_t wsize[2];
967
968 gsize[0] = inputImage->columns;
969 gsize[1] = chunkSize*((inputImage->rows+chunkSize-1)/chunkSize);
970 wsize[0] = 1;
971 wsize[1] = chunkSize;
972
cristy0c832c62014-03-07 22:21:04 +0000973 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +0000974 if (clStatus != CL_SUCCESS)
975 {
cristy0c832c62014-03-07 22:21:04 +0000976 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000977 goto cleanup;
978 }
cristy0c832c62014-03-07 22:21:04 +0000979 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +0000980 }
981 }
982
983 }
984
985 /* get result */
986 if (ALIGNED(filteredPixels,CLPixelPacket))
987 {
988 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +0000989 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 +0000990 }
991 else
992 {
993 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +0000994 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +0000995 }
996 if (clStatus != CL_SUCCESS)
997 {
cristya22457d2013-12-07 14:03:06 +0000998 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000999 goto cleanup;
1000 }
1001
1002 outputReady = MagickTrue;
1003
1004cleanup:
cristya22457d2013-12-07 14:03:06 +00001005 OpenCLLogException(__FUNCTION__,__LINE__,exception);
1006
cristy0c832c62014-03-07 22:21:04 +00001007 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer);
1008 if (tempImageBuffer!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer);
1009 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
1010 if (imageKernelBuffer!=NULL) clEnv->library->clReleaseMemObject(imageKernelBuffer);
cristyf034abb2013-11-24 14:16:14 +00001011 if (blurRowKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurRowKernel);
1012 if (blurColumnKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurColumnKernel);
1013 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
1014 if (kernel!=NULL) DestroyKernelInfo(kernel);
1015 if (outputReady == MagickFalse)
1016 {
1017 if (filteredImage != NULL)
1018 {
1019 DestroyImage(filteredImage);
1020 filteredImage = NULL;
1021 }
1022 }
1023 return filteredImage;
1024}
1025
1026static Image* ComputeBlurImageSection(const Image* inputImage, const ChannelType channel, const double radius, const double sigma, ExceptionInfo *exception)
1027{
1028 MagickBooleanType outputReady;
1029 Image* filteredImage;
1030 MagickCLEnv clEnv;
1031
1032 cl_int clStatus;
1033
1034 const void *inputPixels;
1035 void *filteredPixels;
1036 cl_mem_flags mem_flags;
1037
1038 cl_context context;
1039 cl_mem inputImageBuffer, tempImageBuffer, filteredImageBuffer, imageKernelBuffer;
1040 cl_kernel blurRowKernel, blurColumnKernel;
1041 cl_command_queue queue;
1042
1043 void* hostPtr;
1044 float* kernelBufferPtr;
1045 MagickSizeType length;
1046
1047 char geometry[MaxTextExtent];
1048 KernelInfo* kernel = NULL;
1049 unsigned int kernelWidth;
1050 unsigned int imageColumns, imageRows;
1051
1052 unsigned int i;
1053
1054 context = NULL;
1055 filteredImage = NULL;
1056 inputImageBuffer = NULL;
1057 tempImageBuffer = NULL;
1058 filteredImageBuffer = NULL;
1059 imageKernelBuffer = NULL;
1060 blurRowKernel = NULL;
1061 blurColumnKernel = NULL;
1062 queue = NULL;
1063
1064 outputReady = MagickFalse;
1065
1066 clEnv = GetDefaultOpenCLEnv();
1067 context = GetOpenCLContext(clEnv);
1068 queue = AcquireOpenCLCommandQueue(clEnv);
1069
1070 /* Create and initialize OpenCL buffers. */
1071 {
1072 inputPixels = NULL;
1073 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
1074 if (inputPixels == (const void *) NULL)
1075 {
cristya22457d2013-12-07 14:03:06 +00001076 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
cristyf034abb2013-11-24 14:16:14 +00001077 goto cleanup;
1078 }
1079 /* If the host pointer is aligned to the size of CLPixelPacket,
1080 then use the host buffer directly from the GPU; otherwise,
1081 create a buffer on the GPU and copy the data over */
1082 if (ALIGNED(inputPixels,CLPixelPacket))
1083 {
1084 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
1085 }
1086 else
1087 {
1088 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
1089 }
1090 /* create a CL buffer from image pixel buffer */
1091 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00001092 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001093 if (clStatus != CL_SUCCESS)
1094 {
cristy0c832c62014-03-07 22:21:04 +00001095 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001096 goto cleanup;
1097 }
1098 }
1099
1100 /* create output */
1101 {
1102 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
1103 assert(filteredImage != NULL);
cristy0c832c62014-03-07 22:21:04 +00001104 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +00001105 {
cristya22457d2013-12-07 14:03:06 +00001106 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001107 goto cleanup;
1108 }
1109 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
1110 if (filteredPixels == (void *) NULL)
1111 {
cristya22457d2013-12-07 14:03:06 +00001112 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +00001113 goto cleanup;
1114 }
1115
1116 if (ALIGNED(filteredPixels,CLPixelPacket))
1117 {
1118 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
1119 hostPtr = filteredPixels;
1120 }
1121 else
1122 {
1123 mem_flags = CL_MEM_WRITE_ONLY;
1124 hostPtr = NULL;
1125 }
1126 /* create a CL buffer from image pixel buffer */
1127 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00001128 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001129 if (clStatus != CL_SUCCESS)
1130 {
cristy0c832c62014-03-07 22:21:04 +00001131 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001132 goto cleanup;
1133 }
1134 }
1135
1136 /* create processing kernel */
1137 {
1138 (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
1139 kernel=AcquireKernelInfo(geometry);
1140 if (kernel == (KernelInfo *) NULL)
1141 {
cristya22457d2013-12-07 14:03:06 +00001142 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "MemoryAllocationFailed.",".");
cristyf034abb2013-11-24 14:16:14 +00001143 goto cleanup;
1144 }
1145
cristy0c832c62014-03-07 22:21:04 +00001146 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 +00001147 if (clStatus != CL_SUCCESS)
1148 {
cristy0c832c62014-03-07 22:21:04 +00001149 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001150 goto cleanup;
1151 }
cristy0c832c62014-03-07 22:21:04 +00001152 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 +00001153 if (clStatus != CL_SUCCESS)
1154 {
cristy0c832c62014-03-07 22:21:04 +00001155 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001156 goto cleanup;
1157 }
1158
1159 for (i = 0; i < kernel->width; i++)
1160 {
1161 kernelBufferPtr[i] = (float) kernel->values[i];
1162 }
1163
cristy0c832c62014-03-07 22:21:04 +00001164 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001165 if (clStatus != CL_SUCCESS)
1166 {
cristy0c832c62014-03-07 22:21:04 +00001167 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001168 goto cleanup;
1169 }
1170 }
1171
1172 {
1173 unsigned int offsetRows;
1174 unsigned int sec;
1175
1176 /* create temp buffer */
1177 {
1178 length = inputImage->columns * (inputImage->rows / 2 + 1 + (kernel->width-1) / 2);
cristy0c832c62014-03-07 22:21:04 +00001179 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001180 if (clStatus != CL_SUCCESS)
1181 {
cristy0c832c62014-03-07 22:21:04 +00001182 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001183 goto cleanup;
1184 }
1185 }
1186
1187 /* get the OpenCL kernels */
1188 {
1189 blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRowSection");
1190 if (blurRowKernel == NULL)
1191 {
cristya22457d2013-12-07 14:03:06 +00001192 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001193 goto cleanup;
1194 };
1195
1196 blurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurColumnSection");
1197 if (blurColumnKernel == NULL)
1198 {
cristya22457d2013-12-07 14:03:06 +00001199 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001200 goto cleanup;
1201 };
1202 }
1203
1204 for (sec = 0; sec < 2; sec++)
1205 {
1206 {
1207 /* need logic to decide this value */
1208 int chunkSize = 256;
1209
1210 {
1211 imageColumns = inputImage->columns;
1212 if (sec == 0)
1213 imageRows = inputImage->rows / 2 + (kernel->width-1) / 2;
1214 else
1215 imageRows = (inputImage->rows - inputImage->rows / 2) + (kernel->width-1) / 2;
1216
1217 offsetRows = sec * inputImage->rows / 2;
1218
1219 kernelWidth = kernel->width;
1220
1221 /* set the kernel arguments */
1222 i = 0;
cristy0c832c62014-03-07 22:21:04 +00001223 clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
1224 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
1225 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel);
1226 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
1227 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
1228 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
1229 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows);
1230 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL);
1231 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&offsetRows);
1232 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&sec);
cristyf034abb2013-11-24 14:16:14 +00001233 if (clStatus != CL_SUCCESS)
1234 {
cristy0c832c62014-03-07 22:21:04 +00001235 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001236 goto cleanup;
1237 }
1238 }
1239
1240 /* launch the kernel */
1241 {
1242 size_t gsize[2];
1243 size_t wsize[2];
1244
1245 gsize[0] = chunkSize*((imageColumns+chunkSize-1)/chunkSize);
1246 gsize[1] = imageRows;
1247 wsize[0] = chunkSize;
1248 wsize[1] = 1;
1249
cristy0c832c62014-03-07 22:21:04 +00001250 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001251 if (clStatus != CL_SUCCESS)
1252 {
cristy0c832c62014-03-07 22:21:04 +00001253 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001254 goto cleanup;
1255 }
cristy0c832c62014-03-07 22:21:04 +00001256 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00001257 }
1258 }
1259
1260 {
1261 /* need logic to decide this value */
1262 int chunkSize = 256;
1263
1264 {
1265 imageColumns = inputImage->columns;
1266 if (sec == 0)
1267 imageRows = inputImage->rows / 2;
1268 else
1269 imageRows = (inputImage->rows - inputImage->rows / 2);
1270
1271 offsetRows = sec * inputImage->rows / 2;
1272
1273 kernelWidth = kernel->width;
1274
1275 /* set the kernel arguments */
1276 i = 0;
cristy0c832c62014-03-07 22:21:04 +00001277 clStatus=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
1278 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
1279 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(ChannelType),&channel);
1280 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
1281 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
1282 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
1283 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows);
1284 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_float4)*(chunkSize+kernel->width),(void *)NULL);
1285 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&offsetRows);
1286 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&sec);
cristyf034abb2013-11-24 14:16:14 +00001287 if (clStatus != CL_SUCCESS)
1288 {
cristy0c832c62014-03-07 22:21:04 +00001289 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001290 goto cleanup;
1291 }
1292 }
1293
1294 /* launch the kernel */
1295 {
1296 size_t gsize[2];
1297 size_t wsize[2];
1298
1299 gsize[0] = imageColumns;
1300 gsize[1] = chunkSize*((imageRows+chunkSize-1)/chunkSize);
1301 wsize[0] = 1;
1302 wsize[1] = chunkSize;
1303
cristy0c832c62014-03-07 22:21:04 +00001304 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
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->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001308 goto cleanup;
1309 }
cristy0c832c62014-03-07 22:21:04 +00001310 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00001311 }
1312 }
1313 }
1314
1315 }
1316
1317 /* get result */
1318 if (ALIGNED(filteredPixels,CLPixelPacket))
1319 {
1320 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00001321 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 +00001322 }
1323 else
1324 {
1325 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00001326 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001327 }
1328 if (clStatus != CL_SUCCESS)
1329 {
cristya22457d2013-12-07 14:03:06 +00001330 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001331 goto cleanup;
1332 }
1333
1334 outputReady = MagickTrue;
1335
1336cleanup:
cristya22457d2013-12-07 14:03:06 +00001337 OpenCLLogException(__FUNCTION__,__LINE__,exception);
1338
cristy0c832c62014-03-07 22:21:04 +00001339 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer);
1340 if (tempImageBuffer!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer);
1341 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
1342 if (imageKernelBuffer!=NULL) clEnv->library->clReleaseMemObject(imageKernelBuffer);
cristyf034abb2013-11-24 14:16:14 +00001343 if (blurRowKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurRowKernel);
1344 if (blurColumnKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurColumnKernel);
1345 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
1346 if (kernel!=NULL) DestroyKernelInfo(kernel);
1347 if (outputReady == MagickFalse)
1348 {
1349 if (filteredImage != NULL)
1350 {
1351 DestroyImage(filteredImage);
1352 filteredImage = NULL;
1353 }
1354 }
1355 return filteredImage;
1356}
1357
1358/*
1359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1360% %
1361% %
1362% %
1363% B l u r I m a g e w i t h O p e n C L %
1364% %
1365% %
1366% %
1367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1368%
1369% BlurImage() blurs an image. We convolve the image with a Gaussian operator
1370% of the given radius and standard deviation (sigma). For reasonable results,
1371% the radius should be larger than sigma. Use a radius of 0 and BlurImage()
1372% selects a suitable radius for you.
1373%
1374% The format of the BlurImage method is:
1375%
1376% Image *BlurImage(const Image *image,const double radius,
1377% const double sigma,ExceptionInfo *exception)
1378% Image *BlurImageChannel(const Image *image,const ChannelType channel,
1379% const double radius,const double sigma,ExceptionInfo *exception)
1380%
1381% A description of each parameter follows:
1382%
1383% o image: the image.
1384%
1385% o channel: the channel type.
1386%
1387% o radius: the radius of the Gaussian, in pixels, not counting the center
1388% pixel.
1389%
1390% o sigma: the standard deviation of the Gaussian, in pixels.
1391%
1392% o exception: return any errors or warnings in this structure.
1393%
1394*/
1395
1396MagickExport
1397Image* AccelerateBlurImage(const Image *image, const ChannelType channel, const double radius, const double sigma,ExceptionInfo *exception)
1398{
1399 MagickBooleanType status;
1400 Image* filteredImage = NULL;
1401
1402 assert(image != NULL);
1403 assert(exception != (ExceptionInfo *) NULL);
1404
1405 status = checkOpenCLEnvironment(exception);
1406 if (status == MagickFalse)
1407 return NULL;
1408
dirk5dcb7622013-12-01 10:43:43 +00001409 status = checkAccelerateCondition(image, channel);
cristyf034abb2013-11-24 14:16:14 +00001410 if (status == MagickFalse)
1411 return NULL;
1412
1413 if (splitImage(image) && (image->rows / 2 > radius))
1414 filteredImage = ComputeBlurImageSection(image, channel, radius, sigma, exception);
1415 else
1416 filteredImage = ComputeBlurImage(image, channel, radius, sigma, exception);
1417
cristyf034abb2013-11-24 14:16:14 +00001418 return filteredImage;
1419}
1420
1421
1422static Image* ComputeRadialBlurImage(const Image *inputImage, const ChannelType channel, const double angle, ExceptionInfo *exception)
1423{
1424
1425 MagickBooleanType outputReady;
1426 Image* filteredImage;
1427 MagickCLEnv clEnv;
1428
1429 cl_int clStatus;
1430 size_t global_work_size[2];
1431
1432 cl_context context;
1433 cl_mem_flags mem_flags;
1434 cl_mem inputImageBuffer, filteredImageBuffer, sinThetaBuffer, cosThetaBuffer;
1435 cl_kernel radialBlurKernel;
1436 cl_command_queue queue;
1437
1438 const void *inputPixels;
1439 void *filteredPixels;
1440 void* hostPtr;
1441 float* sinThetaPtr;
1442 float* cosThetaPtr;
1443 MagickSizeType length;
1444 unsigned int matte;
cristy0c832c62014-03-07 22:21:04 +00001445 MagickPixelPacket bias;
cristyf034abb2013-11-24 14:16:14 +00001446 cl_float4 biasPixel;
1447 cl_float2 blurCenter;
1448 float blurRadius;
1449 unsigned int cossin_theta_size;
1450 float offset, theta;
1451
1452 unsigned int i;
1453
1454 outputReady = MagickFalse;
1455 context = NULL;
1456 filteredImage = NULL;
1457 inputImageBuffer = NULL;
1458 filteredImageBuffer = NULL;
1459 sinThetaBuffer = NULL;
1460 cosThetaBuffer = NULL;
1461 queue = NULL;
1462 radialBlurKernel = NULL;
1463
1464
1465 clEnv = GetDefaultOpenCLEnv();
1466 context = GetOpenCLContext(clEnv);
1467
1468
1469 /* Create and initialize OpenCL buffers. */
1470
1471 inputPixels = NULL;
1472 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
1473 if (inputPixels == (const void *) NULL)
1474 {
cristya22457d2013-12-07 14:03:06 +00001475 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
cristyf034abb2013-11-24 14:16:14 +00001476 goto cleanup;
1477 }
1478
1479 /* If the host pointer is aligned to the size of CLPixelPacket,
1480 then use the host buffer directly from the GPU; otherwise,
1481 create a buffer on the GPU and copy the data over */
1482 if (ALIGNED(inputPixels,CLPixelPacket))
1483 {
1484 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
1485 }
1486 else
1487 {
1488 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
1489 }
1490 /* create a CL buffer from image pixel buffer */
1491 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00001492 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001493 if (clStatus != CL_SUCCESS)
1494 {
cristy0c832c62014-03-07 22:21:04 +00001495 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001496 goto cleanup;
1497 }
1498
1499
1500 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
1501 assert(filteredImage != NULL);
cristy0c832c62014-03-07 22:21:04 +00001502 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +00001503 {
cristya22457d2013-12-07 14:03:06 +00001504 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001505 goto cleanup;
1506 }
1507 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
1508 if (filteredPixels == (void *) NULL)
1509 {
cristya22457d2013-12-07 14:03:06 +00001510 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +00001511 goto cleanup;
1512 }
1513
1514 if (ALIGNED(filteredPixels,CLPixelPacket))
1515 {
1516 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
1517 hostPtr = filteredPixels;
1518 }
1519 else
1520 {
1521 mem_flags = CL_MEM_WRITE_ONLY;
1522 hostPtr = NULL;
1523 }
1524 /* create a CL buffer from image pixel buffer */
1525 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00001526 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001527 if (clStatus != CL_SUCCESS)
1528 {
cristy0c832c62014-03-07 22:21:04 +00001529 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001530 goto cleanup;
1531 }
1532
1533 blurCenter.s[0] = (float) (inputImage->columns-1)/2.0;
1534 blurCenter.s[1] = (float) (inputImage->rows-1)/2.0;
1535 blurRadius=hypot(blurCenter.s[0],blurCenter.s[1]);
1536 cossin_theta_size=(unsigned int) fabs(4.0*DegreesToRadians(angle)*sqrt((double)blurRadius)+2UL);
1537
1538 /* create a buffer for sin_theta and cos_theta */
cristy0c832c62014-03-07 22:21:04 +00001539 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 +00001540 if (clStatus != CL_SUCCESS)
1541 {
cristy0c832c62014-03-07 22:21:04 +00001542 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001543 goto cleanup;
1544 }
cristy0c832c62014-03-07 22:21:04 +00001545 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 +00001546 if (clStatus != CL_SUCCESS)
1547 {
cristy0c832c62014-03-07 22:21:04 +00001548 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001549 goto cleanup;
1550 }
1551
1552
1553 queue = AcquireOpenCLCommandQueue(clEnv);
cristy0c832c62014-03-07 22:21:04 +00001554 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 +00001555 if (clStatus != CL_SUCCESS)
1556 {
cristya22457d2013-12-07 14:03:06 +00001557 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnqueuemapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001558 goto cleanup;
1559 }
1560
cristy0c832c62014-03-07 22:21:04 +00001561 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 +00001562 if (clStatus != CL_SUCCESS)
1563 {
cristya22457d2013-12-07 14:03:06 +00001564 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnqueuemapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001565 goto cleanup;
1566 }
1567
1568 theta=DegreesToRadians(angle)/(MagickRealType) (cossin_theta_size-1);
1569 offset=theta*(MagickRealType) (cossin_theta_size-1)/2.0;
1570 for (i=0; i < (ssize_t) cossin_theta_size; i++)
1571 {
1572 cosThetaPtr[i]=(float)cos((double) (theta*i-offset));
1573 sinThetaPtr[i]=(float)sin((double) (theta*i-offset));
1574 }
1575
cristy0c832c62014-03-07 22:21:04 +00001576 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, sinThetaBuffer, sinThetaPtr, 0, NULL, NULL);
1577 clStatus |= clEnv->library->clEnqueueUnmapMemObject(queue, cosThetaBuffer, cosThetaPtr, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001578 if (clStatus != CL_SUCCESS)
1579 {
cristy0c832c62014-03-07 22:21:04 +00001580 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001581 goto cleanup;
1582 }
1583
1584 /* get the OpenCL kernel */
1585 radialBlurKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "RadialBlur");
1586 if (radialBlurKernel == NULL)
1587 {
cristya22457d2013-12-07 14:03:06 +00001588 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001589 goto cleanup;
1590 }
1591
1592
1593 /* set the kernel arguments */
1594 i = 0;
cristy0c832c62014-03-07 22:21:04 +00001595 clStatus=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
1596 clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
cristyf034abb2013-11-24 14:16:14 +00001597
cristy0c832c62014-03-07 22:21:04 +00001598 GetMagickPixelPacket(inputImage,&bias);
cristyf034abb2013-11-24 14:16:14 +00001599 biasPixel.s[0] = bias.red;
1600 biasPixel.s[1] = bias.green;
1601 biasPixel.s[2] = bias.blue;
cristy0c832c62014-03-07 22:21:04 +00001602 biasPixel.s[3] = bias.opacity;
1603 clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_float4), &biasPixel);
1604 clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(ChannelType), &channel);
cristyf034abb2013-11-24 14:16:14 +00001605
cristy0c832c62014-03-07 22:21:04 +00001606 matte = (inputImage->matte != MagickFalse)?1:0;
1607 clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(unsigned int), &matte);
cristyf034abb2013-11-24 14:16:14 +00001608
cristy0c832c62014-03-07 22:21:04 +00001609 clStatus=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_float2), &blurCenter);
cristyf034abb2013-11-24 14:16:14 +00001610
cristy0c832c62014-03-07 22:21:04 +00001611 clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_mem),(void *)&cosThetaBuffer);
1612 clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_mem),(void *)&sinThetaBuffer);
1613 clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(unsigned int), &cossin_theta_size);
cristyf034abb2013-11-24 14:16:14 +00001614 if (clStatus != CL_SUCCESS)
1615 {
cristy0c832c62014-03-07 22:21:04 +00001616 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001617 goto cleanup;
1618 }
1619
1620
1621 global_work_size[0] = inputImage->columns;
1622 global_work_size[1] = inputImage->rows;
1623 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00001624 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, radialBlurKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001625 if (clStatus != CL_SUCCESS)
1626 {
cristy0c832c62014-03-07 22:21:04 +00001627 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001628 goto cleanup;
1629 }
cristy0c832c62014-03-07 22:21:04 +00001630 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00001631
1632 if (ALIGNED(filteredPixels,CLPixelPacket))
1633 {
1634 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00001635 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 +00001636 }
1637 else
1638 {
1639 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00001640 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001641 }
1642 if (clStatus != CL_SUCCESS)
1643 {
cristya22457d2013-12-07 14:03:06 +00001644 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001645 goto cleanup;
1646 }
1647 outputReady = MagickTrue;
1648
1649cleanup:
cristya22457d2013-12-07 14:03:06 +00001650 OpenCLLogException(__FUNCTION__,__LINE__,exception);
1651
cristy0c832c62014-03-07 22:21:04 +00001652 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
1653 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer);
1654 if (sinThetaBuffer!=NULL) clEnv->library->clReleaseMemObject(sinThetaBuffer);
1655 if (cosThetaBuffer!=NULL) clEnv->library->clReleaseMemObject(cosThetaBuffer);
cristyf034abb2013-11-24 14:16:14 +00001656 if (radialBlurKernel!=NULL) RelinquishOpenCLKernel(clEnv, radialBlurKernel);
1657 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
1658 if (outputReady == MagickFalse)
1659 {
1660 if (filteredImage != NULL)
1661 {
1662 DestroyImage(filteredImage);
1663 filteredImage = NULL;
1664 }
1665 }
1666 return filteredImage;
1667}
1668
1669/*
1670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1671% %
1672% %
1673% %
1674% R a d i a l B l u r I m a g e w i t h O p e n C L %
1675% %
1676% %
1677% %
1678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1679%
1680% RadialBlurImage() applies a radial blur to the image.
1681%
1682% Andrew Protano contributed this effect.
1683%
1684% The format of the RadialBlurImage method is:
1685%
1686% Image *RadialBlurImage(const Image *image,const double angle,
1687% ExceptionInfo *exception)
1688% Image *RadialBlurImageChannel(const Image *image,const ChannelType channel,
1689% const double angle,ExceptionInfo *exception)
1690%
1691% A description of each parameter follows:
1692%
1693% o image: the image.
1694%
1695% o channel: the channel type.
1696%
1697% o angle: the angle of the radial blur.
1698%
1699% o exception: return any errors or warnings in this structure.
1700%
1701*/
1702
1703MagickExport
1704Image* AccelerateRadialBlurImage(const Image *image, const ChannelType channel, const double angle, ExceptionInfo *exception)
1705{
1706 MagickBooleanType status;
1707 Image* filteredImage;
1708
1709
1710 assert(image != NULL);
1711 assert(exception != NULL);
1712
1713 status = checkOpenCLEnvironment(exception);
1714 if (status == MagickFalse)
1715 return NULL;
1716
dirk5dcb7622013-12-01 10:43:43 +00001717 status = checkAccelerateCondition(image, channel);
cristyf034abb2013-11-24 14:16:14 +00001718 if (status == MagickFalse)
1719 return NULL;
1720
1721 filteredImage = ComputeRadialBlurImage(image, channel, angle, exception);
cristyf034abb2013-11-24 14:16:14 +00001722 return filteredImage;
1723}
1724
1725
1726
1727static Image* ComputeUnsharpMaskImage(const Image *inputImage, const ChannelType channel,const double radius,const double sigma,
1728 const double gain,const double threshold,ExceptionInfo *exception)
1729{
1730 MagickBooleanType outputReady = MagickFalse;
1731 Image* filteredImage = NULL;
1732 MagickCLEnv clEnv = NULL;
1733
1734 cl_int clStatus;
1735
1736 const void *inputPixels;
1737 void *filteredPixels;
1738 cl_mem_flags mem_flags;
1739
1740 KernelInfo *kernel = NULL;
1741 char geometry[MaxTextExtent];
1742
1743 cl_context context = NULL;
1744 cl_mem inputImageBuffer = NULL;
1745 cl_mem filteredImageBuffer = NULL;
1746 cl_mem tempImageBuffer = NULL;
1747 cl_mem imageKernelBuffer = NULL;
1748 cl_kernel blurRowKernel = NULL;
1749 cl_kernel unsharpMaskBlurColumnKernel = NULL;
1750 cl_command_queue queue = NULL;
1751
1752 void* hostPtr;
1753 float* kernelBufferPtr;
1754 MagickSizeType length;
1755 unsigned int kernelWidth;
1756 float fGain;
1757 float fThreshold;
1758 unsigned int imageColumns, imageRows;
1759 int chunkSize;
1760 unsigned int i;
1761
1762 clEnv = GetDefaultOpenCLEnv();
1763 context = GetOpenCLContext(clEnv);
1764 queue = AcquireOpenCLCommandQueue(clEnv);
1765
1766 /* Create and initialize OpenCL buffers. */
1767 {
1768 inputPixels = NULL;
1769 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
1770 if (inputPixels == (const void *) NULL)
1771 {
cristya22457d2013-12-07 14:03:06 +00001772 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
cristyf034abb2013-11-24 14:16:14 +00001773 goto cleanup;
1774 }
1775
1776 /* If the host pointer is aligned to the size of CLPixelPacket,
1777 then use the host buffer directly from the GPU; otherwise,
1778 create a buffer on the GPU and copy the data over */
1779 if (ALIGNED(inputPixels,CLPixelPacket))
1780 {
1781 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
1782 }
1783 else
1784 {
1785 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
1786 }
1787 /* create a CL buffer from image pixel buffer */
1788 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00001789 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001790 if (clStatus != CL_SUCCESS)
1791 {
cristy0c832c62014-03-07 22:21:04 +00001792 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001793 goto cleanup;
1794 }
1795 }
1796
1797 /* create output */
1798 {
1799 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
1800 assert(filteredImage != NULL);
cristy0c832c62014-03-07 22:21:04 +00001801 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +00001802 {
cristya22457d2013-12-07 14:03:06 +00001803 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001804 goto cleanup;
1805 }
1806 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
1807 if (filteredPixels == (void *) NULL)
1808 {
cristya22457d2013-12-07 14:03:06 +00001809 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +00001810 goto cleanup;
1811 }
1812
1813 if (ALIGNED(filteredPixels,CLPixelPacket))
1814 {
1815 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
1816 hostPtr = filteredPixels;
1817 }
1818 else
1819 {
1820 mem_flags = CL_MEM_WRITE_ONLY;
1821 hostPtr = NULL;
1822 }
1823
1824 /* create a CL buffer from image pixel buffer */
1825 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00001826 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
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->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001830 goto cleanup;
1831 }
1832 }
1833
1834 /* create the blur kernel */
1835 {
1836 (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
1837 kernel=AcquireKernelInfo(geometry);
1838 if (kernel == (KernelInfo *) NULL)
1839 {
cristya22457d2013-12-07 14:03:06 +00001840 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireKernelInfo failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001841 goto cleanup;
1842 }
1843
cristy0c832c62014-03-07 22:21:04 +00001844 imageKernelBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY, kernel->width * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001845 if (clStatus != CL_SUCCESS)
1846 {
cristy0c832c62014-03-07 22:21:04 +00001847 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001848 goto cleanup;
1849 }
1850
1851
cristy0c832c62014-03-07 22:21:04 +00001852 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 +00001853 if (clStatus != CL_SUCCESS)
1854 {
cristy0c832c62014-03-07 22:21:04 +00001855 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001856 goto cleanup;
1857 }
1858 for (i = 0; i < kernel->width; i++)
1859 {
1860 kernelBufferPtr[i] = (float) kernel->values[i];
1861 }
cristy0c832c62014-03-07 22:21:04 +00001862 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001863 if (clStatus != CL_SUCCESS)
1864 {
cristy0c832c62014-03-07 22:21:04 +00001865 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001866 goto cleanup;
1867 }
1868 }
1869
1870 {
1871 /* create temp buffer */
1872 {
1873 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00001874 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001875 if (clStatus != CL_SUCCESS)
1876 {
cristy0c832c62014-03-07 22:21:04 +00001877 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001878 goto cleanup;
1879 }
1880 }
1881
1882 /* get the opencl kernel */
1883 {
1884 blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRow");
1885 if (blurRowKernel == NULL)
1886 {
cristya22457d2013-12-07 14:03:06 +00001887 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001888 goto cleanup;
1889 };
1890
1891 unsharpMaskBlurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "UnsharpMaskBlurColumn");
1892 if (unsharpMaskBlurColumnKernel == NULL)
1893 {
cristya22457d2013-12-07 14:03:06 +00001894 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001895 goto cleanup;
1896 };
1897 }
1898
1899 {
1900 chunkSize = 256;
1901
1902 imageColumns = inputImage->columns;
1903 imageRows = inputImage->rows;
1904
1905 kernelWidth = kernel->width;
1906
1907 /* set the kernel arguments */
1908 i = 0;
cristy0c832c62014-03-07 22:21:04 +00001909 clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
1910 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
1911 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel);
1912 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
1913 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
1914 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
1915 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows);
1916 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL);
cristyf034abb2013-11-24 14:16:14 +00001917 if (clStatus != CL_SUCCESS)
1918 {
cristy0c832c62014-03-07 22:21:04 +00001919 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001920 goto cleanup;
1921 }
1922 }
1923
1924 /* launch the kernel */
1925 {
1926 size_t gsize[2];
1927 size_t wsize[2];
1928
1929 gsize[0] = chunkSize*((inputImage->columns+chunkSize-1)/chunkSize);
1930 gsize[1] = inputImage->rows;
1931 wsize[0] = chunkSize;
1932 wsize[1] = 1;
1933
cristy0c832c62014-03-07 22:21:04 +00001934 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001935 if (clStatus != CL_SUCCESS)
1936 {
cristy0c832c62014-03-07 22:21:04 +00001937 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001938 goto cleanup;
1939 }
cristy0c832c62014-03-07 22:21:04 +00001940 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00001941 }
1942
1943
1944 {
1945 chunkSize = 256;
1946 imageColumns = inputImage->columns;
1947 imageRows = inputImage->rows;
1948 kernelWidth = kernel->width;
1949 fGain = (float)gain;
1950 fThreshold = (float)threshold;
1951
1952 i = 0;
cristy0c832c62014-03-07 22:21:04 +00001953 clStatus=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
1954 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
1955 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
1956 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
1957 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows);
1958 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, (chunkSize+kernelWidth-1)*sizeof(cl_float4),NULL);
1959 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, kernelWidth*sizeof(float),NULL);
1960 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(ChannelType),&channel);
1961 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
1962 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
1963 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fGain);
1964 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fThreshold);
cristyf034abb2013-11-24 14:16:14 +00001965
1966 if (clStatus != CL_SUCCESS)
1967 {
cristy0c832c62014-03-07 22:21:04 +00001968 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001969 goto cleanup;
1970 }
1971 }
1972
1973 /* launch the kernel */
1974 {
1975 size_t gsize[2];
1976 size_t wsize[2];
1977
1978 gsize[0] = inputImage->columns;
1979 gsize[1] = chunkSize*((inputImage->rows+chunkSize-1)/chunkSize);
1980 wsize[0] = 1;
1981 wsize[1] = chunkSize;
1982
cristy0c832c62014-03-07 22:21:04 +00001983 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, unsharpMaskBlurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001984 if (clStatus != CL_SUCCESS)
1985 {
cristy0c832c62014-03-07 22:21:04 +00001986 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001987 goto cleanup;
1988 }
cristy0c832c62014-03-07 22:21:04 +00001989 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00001990 }
1991
1992 }
1993
1994 /* get result */
1995 if (ALIGNED(filteredPixels,CLPixelPacket))
1996 {
1997 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00001998 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 +00001999 }
2000 else
2001 {
2002 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00002003 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002004 }
2005 if (clStatus != CL_SUCCESS)
2006 {
cristya22457d2013-12-07 14:03:06 +00002007 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002008 goto cleanup;
2009 }
2010
2011 outputReady = MagickTrue;
2012
2013cleanup:
cristya22457d2013-12-07 14:03:06 +00002014 OpenCLLogException(__FUNCTION__,__LINE__,exception);
2015
cristyf034abb2013-11-24 14:16:14 +00002016 if (kernel != NULL) kernel=DestroyKernelInfo(kernel);
cristy0c832c62014-03-07 22:21:04 +00002017 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer);
2018 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
2019 if (tempImageBuffer!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer);
2020 if (imageKernelBuffer!=NULL) clEnv->library->clReleaseMemObject(imageKernelBuffer);
cristyf034abb2013-11-24 14:16:14 +00002021 if (blurRowKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurRowKernel);
2022 if (unsharpMaskBlurColumnKernel!=NULL) RelinquishOpenCLKernel(clEnv, unsharpMaskBlurColumnKernel);
2023 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
2024 if (outputReady == MagickFalse)
2025 {
2026 if (filteredImage != NULL)
2027 {
2028 DestroyImage(filteredImage);
2029 filteredImage = NULL;
2030 }
2031 }
2032 return filteredImage;
2033}
2034
2035
2036static Image* ComputeUnsharpMaskImageSection(const Image *inputImage, const ChannelType channel,const double radius,const double sigma,
2037 const double gain,const double threshold,ExceptionInfo *exception)
2038{
2039 MagickBooleanType outputReady = MagickFalse;
2040 Image* filteredImage = NULL;
2041 MagickCLEnv clEnv = NULL;
2042
2043 cl_int clStatus;
2044
2045 const void *inputPixels;
2046 void *filteredPixels;
2047 cl_mem_flags mem_flags;
2048
2049 KernelInfo *kernel = NULL;
2050 char geometry[MaxTextExtent];
2051
2052 cl_context context = NULL;
2053 cl_mem inputImageBuffer = NULL;
2054 cl_mem filteredImageBuffer = NULL;
2055 cl_mem tempImageBuffer = NULL;
2056 cl_mem imageKernelBuffer = NULL;
2057 cl_kernel blurRowKernel = NULL;
2058 cl_kernel unsharpMaskBlurColumnKernel = NULL;
2059 cl_command_queue queue = NULL;
2060
2061 void* hostPtr;
2062 float* kernelBufferPtr;
2063 MagickSizeType length;
2064 unsigned int kernelWidth;
2065 float fGain;
2066 float fThreshold;
2067 unsigned int imageColumns, imageRows;
2068 int chunkSize;
2069 unsigned int i;
2070
2071 clEnv = GetDefaultOpenCLEnv();
2072 context = GetOpenCLContext(clEnv);
2073 queue = AcquireOpenCLCommandQueue(clEnv);
2074
2075 /* Create and initialize OpenCL buffers. */
2076 {
2077 inputPixels = NULL;
2078 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
2079 if (inputPixels == (const void *) NULL)
2080 {
cristya22457d2013-12-07 14:03:06 +00002081 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
cristyf034abb2013-11-24 14:16:14 +00002082 goto cleanup;
2083 }
2084
2085 /* If the host pointer is aligned to the size of CLPixelPacket,
2086 then use the host buffer directly from the GPU; otherwise,
2087 create a buffer on the GPU and copy the data over */
2088 if (ALIGNED(inputPixels,CLPixelPacket))
2089 {
2090 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
2091 }
2092 else
2093 {
2094 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
2095 }
2096 /* create a CL buffer from image pixel buffer */
2097 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00002098 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002099 if (clStatus != CL_SUCCESS)
2100 {
cristy0c832c62014-03-07 22:21:04 +00002101 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002102 goto cleanup;
2103 }
2104 }
2105
2106 /* create output */
2107 {
2108 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
2109 assert(filteredImage != NULL);
cristy0c832c62014-03-07 22:21:04 +00002110 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +00002111 {
cristya22457d2013-12-07 14:03:06 +00002112 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002113 goto cleanup;
2114 }
2115 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
2116 if (filteredPixels == (void *) NULL)
2117 {
cristya22457d2013-12-07 14:03:06 +00002118 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +00002119 goto cleanup;
2120 }
2121
2122 if (ALIGNED(filteredPixels,CLPixelPacket))
2123 {
2124 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
2125 hostPtr = filteredPixels;
2126 }
2127 else
2128 {
2129 mem_flags = CL_MEM_WRITE_ONLY;
2130 hostPtr = NULL;
2131 }
2132
2133 /* create a CL buffer from image pixel buffer */
2134 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00002135 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002136 if (clStatus != CL_SUCCESS)
2137 {
cristy0c832c62014-03-07 22:21:04 +00002138 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002139 goto cleanup;
2140 }
2141 }
2142
2143 /* create the blur kernel */
2144 {
2145 (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
2146 kernel=AcquireKernelInfo(geometry);
2147 if (kernel == (KernelInfo *) NULL)
2148 {
cristya22457d2013-12-07 14:03:06 +00002149 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireKernelInfo failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002150 goto cleanup;
2151 }
2152
cristy0c832c62014-03-07 22:21:04 +00002153 imageKernelBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY, kernel->width * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002154 if (clStatus != CL_SUCCESS)
2155 {
cristy0c832c62014-03-07 22:21:04 +00002156 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002157 goto cleanup;
2158 }
2159
2160
cristy0c832c62014-03-07 22:21:04 +00002161 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 +00002162 if (clStatus != CL_SUCCESS)
2163 {
cristy0c832c62014-03-07 22:21:04 +00002164 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002165 goto cleanup;
2166 }
2167 for (i = 0; i < kernel->width; i++)
2168 {
2169 kernelBufferPtr[i] = (float) kernel->values[i];
2170 }
cristy0c832c62014-03-07 22:21:04 +00002171 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002172 if (clStatus != CL_SUCCESS)
2173 {
cristy0c832c62014-03-07 22:21:04 +00002174 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002175 goto cleanup;
2176 }
2177 }
2178
2179 {
2180 unsigned int offsetRows;
2181 unsigned int sec;
2182
2183 /* create temp buffer */
2184 {
2185 length = inputImage->columns * (inputImage->rows / 2 + 1 + (kernel->width-1) / 2);
cristy0c832c62014-03-07 22:21:04 +00002186 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus);
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->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002190 goto cleanup;
2191 }
2192 }
2193
2194 /* get the opencl kernel */
2195 {
2196 blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRowSection");
2197 if (blurRowKernel == NULL)
2198 {
cristya22457d2013-12-07 14:03:06 +00002199 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002200 goto cleanup;
2201 };
2202
2203 unsharpMaskBlurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "UnsharpMaskBlurColumnSection");
2204 if (unsharpMaskBlurColumnKernel == NULL)
2205 {
cristya22457d2013-12-07 14:03:06 +00002206 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002207 goto cleanup;
2208 };
2209 }
2210
2211 for (sec = 0; sec < 2; sec++)
2212 {
2213 {
2214 chunkSize = 256;
2215
2216 imageColumns = inputImage->columns;
2217 if (sec == 0)
2218 imageRows = inputImage->rows / 2 + (kernel->width-1) / 2;
2219 else
2220 imageRows = (inputImage->rows - inputImage->rows / 2) + (kernel->width-1) / 2;
2221
2222 offsetRows = sec * inputImage->rows / 2;
2223
2224 kernelWidth = kernel->width;
2225
2226 /* set the kernel arguments */
2227 i = 0;
cristy0c832c62014-03-07 22:21:04 +00002228 clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
2229 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
2230 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel);
2231 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
2232 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
2233 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
2234 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows);
2235 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL);
2236 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&offsetRows);
2237 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&sec);
cristyf034abb2013-11-24 14:16:14 +00002238 if (clStatus != CL_SUCCESS)
2239 {
cristy0c832c62014-03-07 22:21:04 +00002240 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002241 goto cleanup;
2242 }
2243 }
2244 /* launch the kernel */
2245 {
2246 size_t gsize[2];
2247 size_t wsize[2];
2248
2249 gsize[0] = chunkSize*((imageColumns+chunkSize-1)/chunkSize);
2250 gsize[1] = imageRows;
2251 wsize[0] = chunkSize;
2252 wsize[1] = 1;
2253
cristy0c832c62014-03-07 22:21:04 +00002254 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002255 if (clStatus != CL_SUCCESS)
2256 {
cristy0c832c62014-03-07 22:21:04 +00002257 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002258 goto cleanup;
2259 }
cristy0c832c62014-03-07 22:21:04 +00002260 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00002261 }
2262
2263
2264 {
2265 chunkSize = 256;
2266
2267 imageColumns = inputImage->columns;
2268 if (sec == 0)
cristya22457d2013-12-07 14:03:06 +00002269 imageRows = inputImage->rows / 2;
cristyf034abb2013-11-24 14:16:14 +00002270 else
2271 imageRows = (inputImage->rows - inputImage->rows / 2);
2272
2273 offsetRows = sec * inputImage->rows / 2;
2274
2275 kernelWidth = kernel->width;
2276
2277 fGain = (float)gain;
2278 fThreshold = (float)threshold;
2279
2280 i = 0;
cristy0c832c62014-03-07 22:21:04 +00002281 clStatus=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
2282 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
2283 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
2284 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
2285 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows);
2286 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, (chunkSize+kernelWidth-1)*sizeof(cl_float4),NULL);
2287 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, kernelWidth*sizeof(float),NULL);
2288 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(ChannelType),&channel);
2289 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
2290 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
2291 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fGain);
2292 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fThreshold);
2293 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&offsetRows);
2294 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&sec);
cristyf034abb2013-11-24 14:16:14 +00002295
2296 if (clStatus != CL_SUCCESS)
2297 {
cristy0c832c62014-03-07 22:21:04 +00002298 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002299 goto cleanup;
2300 }
2301 }
2302
2303 /* launch the kernel */
2304 {
2305 size_t gsize[2];
2306 size_t wsize[2];
2307
2308 gsize[0] = imageColumns;
2309 gsize[1] = chunkSize*((imageRows+chunkSize-1)/chunkSize);
2310 wsize[0] = 1;
2311 wsize[1] = chunkSize;
2312
cristy0c832c62014-03-07 22:21:04 +00002313 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, unsharpMaskBlurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002314 if (clStatus != CL_SUCCESS)
2315 {
cristy0c832c62014-03-07 22:21:04 +00002316 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002317 goto cleanup;
2318 }
cristy0c832c62014-03-07 22:21:04 +00002319 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00002320 }
2321 }
2322 }
2323
2324 /* get result */
2325 if (ALIGNED(filteredPixels,CLPixelPacket))
2326 {
2327 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00002328 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 +00002329 }
2330 else
2331 {
2332 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00002333 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002334 }
2335 if (clStatus != CL_SUCCESS)
2336 {
cristya22457d2013-12-07 14:03:06 +00002337 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002338 goto cleanup;
2339 }
2340
2341 outputReady = MagickTrue;
2342
2343cleanup:
cristya22457d2013-12-07 14:03:06 +00002344 OpenCLLogException(__FUNCTION__,__LINE__,exception);
2345
cristyf034abb2013-11-24 14:16:14 +00002346 if (kernel != NULL) kernel=DestroyKernelInfo(kernel);
cristy0c832c62014-03-07 22:21:04 +00002347 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer);
2348 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
2349 if (tempImageBuffer!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer);
2350 if (imageKernelBuffer!=NULL) clEnv->library->clReleaseMemObject(imageKernelBuffer);
cristyf034abb2013-11-24 14:16:14 +00002351 if (blurRowKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurRowKernel);
2352 if (unsharpMaskBlurColumnKernel!=NULL) RelinquishOpenCLKernel(clEnv, unsharpMaskBlurColumnKernel);
2353 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
2354 if (outputReady == MagickFalse)
2355 {
2356 if (filteredImage != NULL)
2357 {
2358 DestroyImage(filteredImage);
2359 filteredImage = NULL;
2360 }
2361 }
2362 return filteredImage;
2363}
2364
2365
2366/*
2367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2368% %
2369% %
2370% %
2371% U n s h a r p M a s k I m a g e w i t h O p e n C L %
2372% %
2373% %
2374% %
2375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2376%
2377% UnsharpMaskImage() sharpens one or more image channels. We convolve the
2378% image with a Gaussian operator of the given radius and standard deviation
2379% (sigma). For reasonable results, radius should be larger than sigma. Use a
2380% radius of 0 and UnsharpMaskImage() selects a suitable radius for you.
2381%
2382% The format of the UnsharpMaskImage method is:
2383%
2384% Image *UnsharpMaskImage(const Image *image,const double radius,
2385% const double sigma,const double amount,const double threshold,
2386% ExceptionInfo *exception)
2387% Image *UnsharpMaskImageChannel(const Image *image,
2388% const ChannelType channel,const double radius,const double sigma,
2389% const double gain,const double threshold,ExceptionInfo *exception)
2390%
2391% A description of each parameter follows:
2392%
2393% o image: the image.
2394%
2395% o channel: the channel type.
2396%
2397% o radius: the radius of the Gaussian, in pixels, not counting the center
2398% pixel.
2399%
2400% o sigma: the standard deviation of the Gaussian, in pixels.
2401%
2402% o gain: the percentage of the difference between the original and the
2403% blur image that is added back into the original.
2404%
2405% o threshold: the threshold in pixels needed to apply the diffence gain.
2406%
2407% o exception: return any errors or warnings in this structure.
2408%
2409*/
2410
2411
2412MagickExport
2413Image* AccelerateUnsharpMaskImage(const Image *image, const ChannelType channel,const double radius,const double sigma,
2414 const double gain,const double threshold,ExceptionInfo *exception)
2415{
2416 MagickBooleanType status;
2417 Image* filteredImage;
2418
2419
2420 assert(image != NULL);
2421 assert(exception != NULL);
2422
2423 status = checkOpenCLEnvironment(exception);
2424 if (status == MagickFalse)
2425 return NULL;
2426
dirk5dcb7622013-12-01 10:43:43 +00002427 status = checkAccelerateCondition(image, channel);
cristyf034abb2013-11-24 14:16:14 +00002428 if (status == MagickFalse)
2429 return NULL;
2430
2431 if (splitImage(image) && (image->rows / 2 > radius))
2432 filteredImage = ComputeUnsharpMaskImageSection(image,channel,radius,sigma,gain,threshold,exception);
2433 else
2434 filteredImage = ComputeUnsharpMaskImage(image,channel,radius,sigma,gain,threshold,exception);
cristyf034abb2013-11-24 14:16:14 +00002435 return filteredImage;
2436
2437}
2438
cristyf034abb2013-11-24 14:16:14 +00002439static MagickBooleanType resizeHorizontalFilter(cl_mem inputImage
2440 , const unsigned int inputImageColumns, const unsigned int inputImageRows, const unsigned int matte
2441 , cl_mem resizedImage, const unsigned int resizedColumns, const unsigned int resizedRows
2442 , const ResizeFilter* resizeFilter, cl_mem resizeFilterCubicCoefficients, const float xFactor
2443 , MagickCLEnv clEnv, cl_command_queue queue, ExceptionInfo *exception)
2444{
2445 MagickBooleanType status = MagickFalse;
2446
2447 float scale, support;
2448 unsigned int i;
2449 cl_kernel horizontalKernel = NULL;
2450 cl_int clStatus;
2451 size_t global_work_size[2];
2452 size_t local_work_size[2];
2453 int resizeFilterType, resizeWindowType;
2454 float resizeFilterScale, resizeFilterSupport, resizeFilterWindowSupport, resizeFilterBlur;
2455 size_t totalLocalMemorySize;
2456 size_t imageCacheLocalMemorySize, pixelAccumulatorLocalMemorySize
2457 , weightAccumulatorLocalMemorySize, gammaAccumulatorLocalMemorySize;
2458 size_t deviceLocalMemorySize;
2459 int cacheRangeStart, cacheRangeEnd, numCachedPixels;
2460
2461 const unsigned int workgroupSize = 256;
2462 unsigned int pixelPerWorkgroup;
2463 unsigned int chunkSize;
2464
2465 /*
2466 Apply filter to resize vertically from image to resize image.
2467 */
cristye85d0f72013-11-27 02:25:43 +00002468 scale=MAGICK_MAX(1.0/xFactor+MagickEpsilon,1.0);
cristyf034abb2013-11-24 14:16:14 +00002469 support=scale*GetResizeFilterSupport(resizeFilter);
2470 if (support < 0.5)
2471 {
2472 /*
2473 Support too small even for nearest neighbour: Reduce to point
2474 sampling.
2475 */
2476 support=(MagickRealType) 0.5;
2477 scale=1.0;
2478 }
2479 scale=PerceptibleReciprocal(scale);
2480
2481 if (resizedColumns < workgroupSize)
2482 {
2483 chunkSize = 32;
2484 pixelPerWorkgroup = 32;
2485 }
2486 else
2487 {
2488 chunkSize = workgroupSize;
2489 pixelPerWorkgroup = workgroupSize;
2490 }
2491
2492 /* get the local memory size supported by the device */
2493 deviceLocalMemorySize = GetOpenCLDeviceLocalMemorySize(clEnv);
2494
dirke3c5f892013-12-10 06:04:40 +00002495DisableMSCWarning(4127)
cristyf034abb2013-11-24 14:16:14 +00002496 while(1)
dirke3c5f892013-12-10 06:04:40 +00002497RestoreMSCWarning
cristyf034abb2013-11-24 14:16:14 +00002498 {
2499 /* calculate the local memory size needed per workgroup */
2500 cacheRangeStart = (int) (((0 + 0.5)/xFactor+MagickEpsilon)-support+0.5);
2501 cacheRangeEnd = (int) ((((pixelPerWorkgroup-1) + 0.5)/xFactor+MagickEpsilon)+support+0.5);
2502 numCachedPixels = cacheRangeEnd - cacheRangeStart + 1;
2503 imageCacheLocalMemorySize = numCachedPixels * sizeof(CLPixelPacket);
2504 totalLocalMemorySize = imageCacheLocalMemorySize;
2505
2506 /* local size for the pixel accumulator */
2507 pixelAccumulatorLocalMemorySize = chunkSize * sizeof(cl_float4);
2508 totalLocalMemorySize+=pixelAccumulatorLocalMemorySize;
2509
2510 /* local memory size for the weight accumulator */
2511 weightAccumulatorLocalMemorySize = chunkSize * sizeof(float);
2512 totalLocalMemorySize+=weightAccumulatorLocalMemorySize;
2513
2514 /* local memory size for the gamma accumulator */
2515 if (matte == 0)
2516 gammaAccumulatorLocalMemorySize = sizeof(float);
2517 else
2518 gammaAccumulatorLocalMemorySize = chunkSize * sizeof(float);
2519 totalLocalMemorySize+=gammaAccumulatorLocalMemorySize;
2520
2521 if (totalLocalMemorySize <= deviceLocalMemorySize)
2522 break;
2523 else
2524 {
2525 pixelPerWorkgroup = pixelPerWorkgroup/2;
2526 chunkSize = chunkSize/2;
2527 if (pixelPerWorkgroup == 0
2528 || chunkSize == 0)
2529 {
2530 /* quit, fallback to CPU */
2531 goto cleanup;
2532 }
2533 }
2534 }
2535
2536 resizeFilterType = (int)GetResizeFilterWeightingType(resizeFilter);
2537 resizeWindowType = (int)GetResizeFilterWindowWeightingType(resizeFilter);
2538
2539
2540 if (resizeFilterType == SincFastWeightingFunction
2541 && resizeWindowType == SincFastWeightingFunction)
2542 {
2543 horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeHorizontalFilterSinc");
2544 }
2545 else
2546 {
2547 horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeHorizontalFilter");
2548 }
2549 if (horizontalKernel == NULL)
2550 {
cristya22457d2013-12-07 14:03:06 +00002551 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002552 goto cleanup;
2553 }
2554
2555 i = 0;
cristy0c832c62014-03-07 22:21:04 +00002556 clStatus = clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&inputImage);
2557 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&inputImageColumns);
2558 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&inputImageRows);
2559 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&matte);
2560 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&xFactor);
2561 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizedImage);
cristyf034abb2013-11-24 14:16:14 +00002562
cristy0c832c62014-03-07 22:21:04 +00002563 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedColumns);
2564 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedRows);
cristyf034abb2013-11-24 14:16:14 +00002565
cristy0c832c62014-03-07 22:21:04 +00002566 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeFilterType);
2567 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeWindowType);
2568 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizeFilterCubicCoefficients);
cristyf034abb2013-11-24 14:16:14 +00002569
2570 resizeFilterScale = (float) GetResizeFilterScale(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00002571 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterScale);
cristyf034abb2013-11-24 14:16:14 +00002572
2573 resizeFilterSupport = (float) GetResizeFilterSupport(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00002574 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterSupport);
cristyf034abb2013-11-24 14:16:14 +00002575
2576 resizeFilterWindowSupport = (float) GetResizeFilterWindowSupport(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00002577 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterWindowSupport);
cristyf034abb2013-11-24 14:16:14 +00002578
2579 resizeFilterBlur = (float) GetResizeFilterBlur(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00002580 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterBlur);
cristyf034abb2013-11-24 14:16:14 +00002581
2582
cristy0c832c62014-03-07 22:21:04 +00002583 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, imageCacheLocalMemorySize, NULL);
2584 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), &numCachedPixels);
2585 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &pixelPerWorkgroup);
2586 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &chunkSize);
cristyf034abb2013-11-24 14:16:14 +00002587
2588
cristy0c832c62014-03-07 22:21:04 +00002589 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, pixelAccumulatorLocalMemorySize, NULL);
2590 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, weightAccumulatorLocalMemorySize, NULL);
2591 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, gammaAccumulatorLocalMemorySize, NULL);
cristyf034abb2013-11-24 14:16:14 +00002592
2593 if (clStatus != CL_SUCCESS)
2594 {
cristy0c832c62014-03-07 22:21:04 +00002595 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002596 goto cleanup;
2597 }
2598
2599 global_work_size[0] = (resizedColumns+pixelPerWorkgroup-1)/pixelPerWorkgroup*workgroupSize;
2600 global_work_size[1] = resizedRows;
2601
2602 local_work_size[0] = workgroupSize;
2603 local_work_size[1] = 1;
cristy0c832c62014-03-07 22:21:04 +00002604 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, horizontalKernel, 2, NULL, global_work_size, local_work_size, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002605 if (clStatus != CL_SUCCESS)
2606 {
cristy0c832c62014-03-07 22:21:04 +00002607 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002608 goto cleanup;
2609 }
cristy0c832c62014-03-07 22:21:04 +00002610 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00002611 status = MagickTrue;
2612
2613
2614cleanup:
cristya22457d2013-12-07 14:03:06 +00002615 OpenCLLogException(__FUNCTION__,__LINE__,exception);
2616
cristyf034abb2013-11-24 14:16:14 +00002617 if (horizontalKernel != NULL) RelinquishOpenCLKernel(clEnv, horizontalKernel);
2618
2619 return status;
2620}
2621
2622
2623static MagickBooleanType resizeVerticalFilter(cl_mem inputImage
2624 , const unsigned int inputImageColumns, const unsigned int inputImageRows, const unsigned int matte
2625 , cl_mem resizedImage, const unsigned int resizedColumns, const unsigned int resizedRows
2626 , const ResizeFilter* resizeFilter, cl_mem resizeFilterCubicCoefficients, const float yFactor
2627 , MagickCLEnv clEnv, cl_command_queue queue, ExceptionInfo *exception)
2628{
2629 MagickBooleanType status = MagickFalse;
2630
2631 float scale, support;
2632 unsigned int i;
2633 cl_kernel horizontalKernel = NULL;
2634 cl_int clStatus;
2635 size_t global_work_size[2];
2636 size_t local_work_size[2];
2637 int resizeFilterType, resizeWindowType;
2638 float resizeFilterScale, resizeFilterSupport, resizeFilterWindowSupport, resizeFilterBlur;
2639 size_t totalLocalMemorySize;
2640 size_t imageCacheLocalMemorySize, pixelAccumulatorLocalMemorySize
2641 , weightAccumulatorLocalMemorySize, gammaAccumulatorLocalMemorySize;
2642 size_t deviceLocalMemorySize;
2643 int cacheRangeStart, cacheRangeEnd, numCachedPixels;
2644
2645 const unsigned int workgroupSize = 256;
2646 unsigned int pixelPerWorkgroup;
2647 unsigned int chunkSize;
2648
2649 /*
2650 Apply filter to resize vertically from image to resize image.
2651 */
cristye85d0f72013-11-27 02:25:43 +00002652 scale=MAGICK_MAX(1.0/yFactor+MagickEpsilon,1.0);
cristyf034abb2013-11-24 14:16:14 +00002653 support=scale*GetResizeFilterSupport(resizeFilter);
2654 if (support < 0.5)
2655 {
2656 /*
2657 Support too small even for nearest neighbour: Reduce to point
2658 sampling.
2659 */
2660 support=(MagickRealType) 0.5;
2661 scale=1.0;
2662 }
2663 scale=PerceptibleReciprocal(scale);
2664
2665 if (resizedRows < workgroupSize)
2666 {
2667 chunkSize = 32;
2668 pixelPerWorkgroup = 32;
2669 }
2670 else
2671 {
2672 chunkSize = workgroupSize;
2673 pixelPerWorkgroup = workgroupSize;
2674 }
2675
2676 /* get the local memory size supported by the device */
2677 deviceLocalMemorySize = GetOpenCLDeviceLocalMemorySize(clEnv);
2678
dirke3c5f892013-12-10 06:04:40 +00002679DisableMSCWarning(4127)
cristyf034abb2013-11-24 14:16:14 +00002680 while(1)
dirke3c5f892013-12-10 06:04:40 +00002681RestoreMSCWarning
cristyf034abb2013-11-24 14:16:14 +00002682 {
2683 /* calculate the local memory size needed per workgroup */
2684 cacheRangeStart = (int) (((0 + 0.5)/yFactor+MagickEpsilon)-support+0.5);
2685 cacheRangeEnd = (int) ((((pixelPerWorkgroup-1) + 0.5)/yFactor+MagickEpsilon)+support+0.5);
2686 numCachedPixels = cacheRangeEnd - cacheRangeStart + 1;
2687 imageCacheLocalMemorySize = numCachedPixels * sizeof(CLPixelPacket);
2688 totalLocalMemorySize = imageCacheLocalMemorySize;
2689
2690 /* local size for the pixel accumulator */
2691 pixelAccumulatorLocalMemorySize = chunkSize * sizeof(cl_float4);
2692 totalLocalMemorySize+=pixelAccumulatorLocalMemorySize;
2693
2694 /* local memory size for the weight accumulator */
2695 weightAccumulatorLocalMemorySize = chunkSize * sizeof(float);
2696 totalLocalMemorySize+=weightAccumulatorLocalMemorySize;
2697
2698 /* local memory size for the gamma accumulator */
2699 if (matte == 0)
2700 gammaAccumulatorLocalMemorySize = sizeof(float);
2701 else
2702 gammaAccumulatorLocalMemorySize = chunkSize * sizeof(float);
2703 totalLocalMemorySize+=gammaAccumulatorLocalMemorySize;
2704
2705 if (totalLocalMemorySize <= deviceLocalMemorySize)
2706 break;
2707 else
2708 {
2709 pixelPerWorkgroup = pixelPerWorkgroup/2;
2710 chunkSize = chunkSize/2;
2711 if (pixelPerWorkgroup == 0
2712 || chunkSize == 0)
2713 {
2714 /* quit, fallback to CPU */
2715 goto cleanup;
2716 }
2717 }
2718 }
2719
2720 resizeFilterType = (int)GetResizeFilterWeightingType(resizeFilter);
2721 resizeWindowType = (int)GetResizeFilterWindowWeightingType(resizeFilter);
2722
2723 if (resizeFilterType == SincFastWeightingFunction
2724 && resizeWindowType == SincFastWeightingFunction)
2725 horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeVerticalFilterSinc");
2726 else
2727 horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeVerticalFilter");
2728
2729 if (horizontalKernel == NULL)
2730 {
cristya22457d2013-12-07 14:03:06 +00002731 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002732 goto cleanup;
2733 }
2734
2735 i = 0;
cristy0c832c62014-03-07 22:21:04 +00002736 clStatus = clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&inputImage);
2737 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&inputImageColumns);
2738 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&inputImageRows);
2739 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&matte);
2740 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&yFactor);
2741 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizedImage);
cristyf034abb2013-11-24 14:16:14 +00002742
cristy0c832c62014-03-07 22:21:04 +00002743 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedColumns);
2744 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedRows);
cristyf034abb2013-11-24 14:16:14 +00002745
cristy0c832c62014-03-07 22:21:04 +00002746 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeFilterType);
2747 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeWindowType);
2748 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizeFilterCubicCoefficients);
cristyf034abb2013-11-24 14:16:14 +00002749
2750 resizeFilterScale = (float) GetResizeFilterScale(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00002751 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterScale);
cristyf034abb2013-11-24 14:16:14 +00002752
2753 resizeFilterSupport = (float) GetResizeFilterSupport(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00002754 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterSupport);
cristyf034abb2013-11-24 14:16:14 +00002755
2756 resizeFilterWindowSupport = (float) GetResizeFilterWindowSupport(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00002757 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterWindowSupport);
cristyf034abb2013-11-24 14:16:14 +00002758
2759 resizeFilterBlur = (float) GetResizeFilterBlur(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00002760 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterBlur);
cristyf034abb2013-11-24 14:16:14 +00002761
2762
cristy0c832c62014-03-07 22:21:04 +00002763 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, imageCacheLocalMemorySize, NULL);
2764 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), &numCachedPixels);
2765 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &pixelPerWorkgroup);
2766 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &chunkSize);
cristyf034abb2013-11-24 14:16:14 +00002767
2768
cristy0c832c62014-03-07 22:21:04 +00002769 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, pixelAccumulatorLocalMemorySize, NULL);
2770 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, weightAccumulatorLocalMemorySize, NULL);
2771 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, gammaAccumulatorLocalMemorySize, NULL);
cristyf034abb2013-11-24 14:16:14 +00002772
2773 if (clStatus != CL_SUCCESS)
2774 {
cristy0c832c62014-03-07 22:21:04 +00002775 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002776 goto cleanup;
2777 }
2778
2779 global_work_size[0] = resizedColumns;
2780 global_work_size[1] = (resizedRows+pixelPerWorkgroup-1)/pixelPerWorkgroup*workgroupSize;
2781
2782 local_work_size[0] = 1;
2783 local_work_size[1] = workgroupSize;
cristy0c832c62014-03-07 22:21:04 +00002784 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, horizontalKernel, 2, NULL, global_work_size, local_work_size, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002785 if (clStatus != CL_SUCCESS)
2786 {
cristy0c832c62014-03-07 22:21:04 +00002787 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002788 goto cleanup;
2789 }
cristy0c832c62014-03-07 22:21:04 +00002790 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00002791 status = MagickTrue;
2792
2793
2794cleanup:
cristya22457d2013-12-07 14:03:06 +00002795 OpenCLLogException(__FUNCTION__,__LINE__,exception);
2796
cristyf034abb2013-11-24 14:16:14 +00002797 if (horizontalKernel != NULL) RelinquishOpenCLKernel(clEnv, horizontalKernel);
2798
2799 return status;
2800}
2801
2802
2803
2804static Image* ComputeResizeImage(const Image* inputImage, const size_t resizedColumns, const size_t resizedRows
2805 , const ResizeFilter* resizeFilter, ExceptionInfo *exception)
2806{
2807
2808 MagickBooleanType outputReady = MagickFalse;
2809 Image* filteredImage = NULL;
2810 MagickCLEnv clEnv = NULL;
2811
2812 cl_int clStatus;
2813 MagickBooleanType status;
2814 const void *inputPixels;
2815 void* filteredPixels;
2816 void* hostPtr;
2817 const MagickRealType* resizeFilterCoefficient;
2818 float* mappedCoefficientBuffer;
2819 float xFactor, yFactor;
2820 MagickSizeType length;
2821
2822 cl_mem_flags mem_flags;
2823 cl_context context = NULL;
2824 cl_mem inputImageBuffer = NULL;
2825 cl_mem tempImageBuffer = NULL;
2826 cl_mem filteredImageBuffer = NULL;
2827 cl_mem cubicCoefficientsBuffer = NULL;
2828 cl_command_queue queue = NULL;
2829
2830 unsigned int i;
2831
2832 clEnv = GetDefaultOpenCLEnv();
2833 context = GetOpenCLContext(clEnv);
2834
2835 /* Create and initialize OpenCL buffers. */
2836 inputPixels = NULL;
2837 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
2838 if (inputPixels == (const void *) NULL)
2839 {
cristya22457d2013-12-07 14:03:06 +00002840 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
cristyf034abb2013-11-24 14:16:14 +00002841 goto cleanup;
2842 }
2843
2844 /* If the host pointer is aligned to the size of CLPixelPacket,
2845 then use the host buffer directly from the GPU; otherwise,
2846 create a buffer on the GPU and copy the data over */
2847 if (ALIGNED(inputPixels,CLPixelPacket))
2848 {
2849 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
2850 }
2851 else
2852 {
2853 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
2854 }
2855 /* create a CL buffer from image pixel buffer */
2856 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00002857 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002858 if (clStatus != CL_SUCCESS)
2859 {
cristy0c832c62014-03-07 22:21:04 +00002860 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002861 goto cleanup;
2862 }
2863
cristy0c832c62014-03-07 22:21:04 +00002864 cubicCoefficientsBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY, 7 * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002865 if (clStatus != CL_SUCCESS)
2866 {
cristy0c832c62014-03-07 22:21:04 +00002867 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002868 goto cleanup;
2869 }
2870 queue = AcquireOpenCLCommandQueue(clEnv);
cristy0c832c62014-03-07 22:21:04 +00002871 mappedCoefficientBuffer = (float*)clEnv->library->clEnqueueMapBuffer(queue, cubicCoefficientsBuffer, CL_TRUE, CL_MAP_WRITE, 0, 7 * sizeof(float)
cristyf034abb2013-11-24 14:16:14 +00002872 , 0, NULL, NULL, &clStatus);
2873 if (clStatus != CL_SUCCESS)
2874 {
cristy0c832c62014-03-07 22:21:04 +00002875 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002876 goto cleanup;
2877 }
2878 resizeFilterCoefficient = GetResizeFilterCoefficient(resizeFilter);
2879 for (i = 0; i < 7; i++)
2880 {
2881 mappedCoefficientBuffer[i] = (float) resizeFilterCoefficient[i];
2882 }
cristy0c832c62014-03-07 22:21:04 +00002883 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, cubicCoefficientsBuffer, mappedCoefficientBuffer, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002884 if (clStatus != CL_SUCCESS)
2885 {
cristy0c832c62014-03-07 22:21:04 +00002886 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002887 goto cleanup;
2888 }
2889
2890 filteredImage = CloneImage(inputImage,resizedColumns,resizedRows,MagickTrue,exception);
2891 if (filteredImage == NULL)
2892 goto cleanup;
2893
cristy0c832c62014-03-07 22:21:04 +00002894 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +00002895 {
cristya22457d2013-12-07 14:03:06 +00002896 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002897 goto cleanup;
2898 }
2899 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
2900 if (filteredPixels == (void *) NULL)
2901 {
cristya22457d2013-12-07 14:03:06 +00002902 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +00002903 goto cleanup;
2904 }
2905
2906 if (ALIGNED(filteredPixels,CLPixelPacket))
2907 {
2908 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
2909 hostPtr = filteredPixels;
2910 }
2911 else
2912 {
2913 mem_flags = CL_MEM_WRITE_ONLY;
2914 hostPtr = NULL;
2915 }
2916
2917 /* create a CL buffer from image pixel buffer */
2918 length = filteredImage->columns * filteredImage->rows;
cristy0c832c62014-03-07 22:21:04 +00002919 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002920 if (clStatus != CL_SUCCESS)
2921 {
cristy0c832c62014-03-07 22:21:04 +00002922 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002923 goto cleanup;
2924 }
2925
2926 xFactor=(float) resizedColumns/(float) inputImage->columns;
2927 yFactor=(float) resizedRows/(float) inputImage->rows;
2928 if (xFactor > yFactor)
2929 {
2930
2931 length = resizedColumns*inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00002932 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length*sizeof(CLPixelPacket), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002933 if (clStatus != CL_SUCCESS)
2934 {
cristy0c832c62014-03-07 22:21:04 +00002935 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002936 goto cleanup;
2937 }
2938
cristy0c832c62014-03-07 22:21:04 +00002939 status = resizeHorizontalFilter(inputImageBuffer, inputImage->columns, inputImage->rows, (inputImage->matte != MagickFalse)?1:0
cristyf034abb2013-11-24 14:16:14 +00002940 , tempImageBuffer, resizedColumns, inputImage->rows
2941 , resizeFilter, cubicCoefficientsBuffer
2942 , xFactor, clEnv, queue, exception);
2943 if (status != MagickTrue)
2944 goto cleanup;
2945
cristy0c832c62014-03-07 22:21:04 +00002946 status = resizeVerticalFilter(tempImageBuffer, resizedColumns, inputImage->rows, (inputImage->matte != MagickFalse)?1:0
cristyf034abb2013-11-24 14:16:14 +00002947 , filteredImageBuffer, resizedColumns, resizedRows
2948 , resizeFilter, cubicCoefficientsBuffer
2949 , yFactor, clEnv, queue, exception);
2950 if (status != MagickTrue)
2951 goto cleanup;
2952 }
2953 else
2954 {
2955 length = inputImage->columns*resizedRows;
cristy0c832c62014-03-07 22:21:04 +00002956 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length*sizeof(CLPixelPacket), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002957 if (clStatus != CL_SUCCESS)
2958 {
cristy0c832c62014-03-07 22:21:04 +00002959 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002960 goto cleanup;
2961 }
2962
cristy0c832c62014-03-07 22:21:04 +00002963 status = resizeVerticalFilter(inputImageBuffer, inputImage->columns, inputImage->rows, (inputImage->matte != MagickFalse)?1:0
cristyf034abb2013-11-24 14:16:14 +00002964 , tempImageBuffer, inputImage->columns, resizedRows
2965 , resizeFilter, cubicCoefficientsBuffer
2966 , yFactor, clEnv, queue, exception);
2967 if (status != MagickTrue)
2968 goto cleanup;
2969
cristy0c832c62014-03-07 22:21:04 +00002970 status = resizeHorizontalFilter(tempImageBuffer, inputImage->columns, resizedRows, (inputImage->matte != MagickFalse)?1:0
cristyf034abb2013-11-24 14:16:14 +00002971 , filteredImageBuffer, resizedColumns, resizedRows
2972 , resizeFilter, cubicCoefficientsBuffer
2973 , xFactor, clEnv, queue, exception);
2974 if (status != MagickTrue)
2975 goto cleanup;
2976 }
2977 length = resizedColumns*resizedRows;
2978 if (ALIGNED(filteredPixels,CLPixelPacket))
2979 {
cristy0c832c62014-03-07 22:21:04 +00002980 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 +00002981 }
2982 else
2983 {
cristy0c832c62014-03-07 22:21:04 +00002984 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002985 }
2986 if (clStatus != CL_SUCCESS)
2987 {
cristya22457d2013-12-07 14:03:06 +00002988 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002989 goto cleanup;
2990 }
2991 outputReady = MagickTrue;
2992
2993cleanup:
cristya22457d2013-12-07 14:03:06 +00002994 OpenCLLogException(__FUNCTION__,__LINE__,exception);
2995
cristy0c832c62014-03-07 22:21:04 +00002996 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer);
2997 if (tempImageBuffer!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer);
2998 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
2999 if (cubicCoefficientsBuffer!=NULL) clEnv->library->clReleaseMemObject(cubicCoefficientsBuffer);
cristyf034abb2013-11-24 14:16:14 +00003000 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
3001 if (outputReady == MagickFalse)
3002 {
3003 if (filteredImage != NULL)
3004 {
3005 DestroyImage(filteredImage);
3006 filteredImage = NULL;
3007 }
3008 }
3009
3010 return filteredImage;
3011}
3012
3013const ResizeWeightingFunctionType supportedResizeWeighting[] =
3014{
3015 BoxWeightingFunction
3016 ,TriangleWeightingFunction
3017 ,HanningWeightingFunction
3018 ,HammingWeightingFunction
3019 ,BlackmanWeightingFunction
3020 ,CubicBCWeightingFunction
3021 ,SincWeightingFunction
3022 ,SincFastWeightingFunction
3023 ,LastWeightingFunction
3024};
3025
3026static MagickBooleanType gpuSupportedResizeWeighting(ResizeWeightingFunctionType f)
3027{
3028 MagickBooleanType supported = MagickFalse;
3029 unsigned int i;
3030 for (i = 0; ;i++)
3031 {
3032 if (supportedResizeWeighting[i] == LastWeightingFunction)
3033 break;
3034 if (supportedResizeWeighting[i] == f)
3035 {
3036 supported = MagickTrue;
3037 break;
3038 }
3039 }
3040 return supported;
3041}
3042
3043
3044/*
3045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3046% %
3047% %
3048% %
3049% A c c e l e r a t e R e s i z e I m a g e %
3050% %
3051% %
3052% %
3053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3054%
3055% AccelerateResizeImage() is an OpenCL implementation of ResizeImage()
3056%
3057% AccelerateResizeImage() scales an image to the desired dimensions, using the given
3058% filter (see AcquireFilterInfo()).
3059%
3060% If an undefined filter is given the filter defaults to Mitchell for a
3061% colormapped image, a image with a matte channel, or if the image is
3062% enlarged. Otherwise the filter defaults to a Lanczos.
3063%
3064% AccelerateResizeImage() was inspired by Paul Heckbert's "zoom" program.
3065%
3066% The format of the AccelerateResizeImage method is:
3067%
3068% Image *ResizeImage(Image *image,const size_t columns,
3069% const size_t rows, const ResizeFilter* filter,
cristy3f6d1482010-01-20 21:01:21 +00003070% ExceptionInfo *exception)
3071%
3072% A description of each parameter follows:
3073%
3074% o image: the image.
3075%
cristyf034abb2013-11-24 14:16:14 +00003076% o columns: the number of columns in the scaled image.
cristy3f6d1482010-01-20 21:01:21 +00003077%
cristyf034abb2013-11-24 14:16:14 +00003078% o rows: the number of rows in the scaled image.
3079%
3080% o filter: Image filter to use.
cristy3f6d1482010-01-20 21:01:21 +00003081%
3082% o exception: return any errors or warnings in this structure.
3083%
3084*/
cristyd43a46b2010-01-21 02:13:41 +00003085
cristyf034abb2013-11-24 14:16:14 +00003086MagickExport
3087Image* AccelerateResizeImage(const Image* image, const size_t resizedColumns, const size_t resizedRows
3088 , const ResizeFilter* resizeFilter, ExceptionInfo *exception)
cristyd43a46b2010-01-21 02:13:41 +00003089{
cristyf034abb2013-11-24 14:16:14 +00003090 MagickBooleanType status;
3091 Image* filteredImage;
cristyd43a46b2010-01-21 02:13:41 +00003092
cristyf034abb2013-11-24 14:16:14 +00003093 assert(image != NULL);
3094 assert(resizeFilter != NULL);
cristyd43a46b2010-01-21 02:13:41 +00003095
cristyf034abb2013-11-24 14:16:14 +00003096 status = checkOpenCLEnvironment(exception);
3097 if (status == MagickFalse)
3098 return NULL;
cristyd43a46b2010-01-21 02:13:41 +00003099
dirk5dcb7622013-12-01 10:43:43 +00003100 status = checkAccelerateCondition(image, AllChannels);
cristyf034abb2013-11-24 14:16:14 +00003101 if (status == MagickFalse)
3102 return NULL;
cristyd43a46b2010-01-21 02:13:41 +00003103
cristyf034abb2013-11-24 14:16:14 +00003104 if (gpuSupportedResizeWeighting(GetResizeFilterWeightingType(resizeFilter)) == MagickFalse
3105 || gpuSupportedResizeWeighting(GetResizeFilterWindowWeightingType(resizeFilter)) == MagickFalse)
3106 return NULL;
cristyd43a46b2010-01-21 02:13:41 +00003107
cristyf034abb2013-11-24 14:16:14 +00003108 filteredImage = ComputeResizeImage(image,resizedColumns,resizedRows,resizeFilter,exception);
cristyf034abb2013-11-24 14:16:14 +00003109 return filteredImage;
cristyd43a46b2010-01-21 02:13:41 +00003110
cristyd43a46b2010-01-21 02:13:41 +00003111}
3112
cristyd43a46b2010-01-21 02:13:41 +00003113
cristyf034abb2013-11-24 14:16:14 +00003114static MagickBooleanType ComputeContrastImage(Image *inputImage, const MagickBooleanType sharpen, ExceptionInfo *exception)
3115{
3116 MagickBooleanType outputReady = MagickFalse;
3117 MagickCLEnv clEnv = NULL;
3118
3119 cl_int clStatus;
3120 size_t global_work_size[2];
3121
3122 void *inputPixels = NULL;
3123 MagickSizeType length;
3124 unsigned int uSharpen;
3125 unsigned int i;
3126
3127 cl_mem_flags mem_flags;
3128 cl_context context = NULL;
3129 cl_mem inputImageBuffer = NULL;
3130 cl_kernel filterKernel = NULL;
3131 cl_command_queue queue = NULL;
3132
3133 clEnv = GetDefaultOpenCLEnv();
3134 context = GetOpenCLContext(clEnv);
3135
3136 /* Create and initialize OpenCL buffers. */
3137 inputPixels = GetPixelCachePixels(inputImage, &length, exception);
3138 if (inputPixels == (void *) NULL)
3139 {
cristya22457d2013-12-07 14:03:06 +00003140 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
cristyf034abb2013-11-24 14:16:14 +00003141 goto cleanup;
3142 }
3143
3144 /* If the host pointer is aligned to the size of CLPixelPacket,
3145 then use the host buffer directly from the GPU; otherwise,
3146 create a buffer on the GPU and copy the data over */
3147 if (ALIGNED(inputPixels,CLPixelPacket))
3148 {
3149 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
3150 }
3151 else
3152 {
3153 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
3154 }
3155 /* create a CL buffer from image pixel buffer */
3156 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00003157 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00003158 if (clStatus != CL_SUCCESS)
3159 {
cristy0c832c62014-03-07 22:21:04 +00003160 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00003161 goto cleanup;
3162 }
3163
3164 filterKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Contrast");
3165 if (filterKernel == NULL)
3166 {
cristya22457d2013-12-07 14:03:06 +00003167 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003168 goto cleanup;
3169 }
3170
3171 i = 0;
cristy0c832c62014-03-07 22:21:04 +00003172 clStatus=clEnv->library->clSetKernelArg(filterKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
cristyf034abb2013-11-24 14:16:14 +00003173
3174 uSharpen = (sharpen == MagickFalse)?0:1;
cristy0c832c62014-03-07 22:21:04 +00003175 clStatus|=clEnv->library->clSetKernelArg(filterKernel,i++,sizeof(cl_uint),&uSharpen);
cristyf034abb2013-11-24 14:16:14 +00003176 if (clStatus != CL_SUCCESS)
3177 {
cristy0c832c62014-03-07 22:21:04 +00003178 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003179 goto cleanup;
3180 }
3181
3182 global_work_size[0] = inputImage->columns;
3183 global_work_size[1] = inputImage->rows;
3184 /* launch the kernel */
3185 queue = AcquireOpenCLCommandQueue(clEnv);
cristy0c832c62014-03-07 22:21:04 +00003186 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, filterKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00003187 if (clStatus != CL_SUCCESS)
3188 {
cristy0c832c62014-03-07 22:21:04 +00003189 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003190 goto cleanup;
3191 }
cristy0c832c62014-03-07 22:21:04 +00003192 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00003193
3194 if (ALIGNED(inputPixels,CLPixelPacket))
3195 {
3196 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00003197 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00003198 }
3199 else
3200 {
3201 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00003202 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00003203 }
3204 if (clStatus != CL_SUCCESS)
3205 {
cristya22457d2013-12-07 14:03:06 +00003206 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003207 goto cleanup;
3208 }
3209 outputReady = MagickTrue;
3210
3211cleanup:
cristya22457d2013-12-07 14:03:06 +00003212 OpenCLLogException(__FUNCTION__,__LINE__,exception);
cristyf034abb2013-11-24 14:16:14 +00003213
cristy0c832c62014-03-07 22:21:04 +00003214 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer);
cristyf034abb2013-11-24 14:16:14 +00003215 if (filterKernel!=NULL) RelinquishOpenCLKernel(clEnv, filterKernel);
3216 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
3217 return outputReady;
3218}
3219
3220/*
3221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3222% %
3223% %
3224% %
3225% C o n t r a s t I m a g e w i t h O p e n C L %
3226% %
3227% %
3228% %
3229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3230%
3231% ContrastImage() enhances the intensity differences between the lighter and
3232% darker elements of the image. Set sharpen to a MagickTrue to increase the
3233% image contrast otherwise the contrast is reduced.
3234%
3235% The format of the ContrastImage method is:
3236%
3237% MagickBooleanType ContrastImage(Image *image,
3238% const MagickBooleanType sharpen)
3239%
3240% A description of each parameter follows:
3241%
3242% o image: the image.
3243%
3244% o sharpen: Increase or decrease image contrast.
3245%
3246*/
3247
3248MagickExport
3249MagickBooleanType AccelerateContrastImage(Image* image, const MagickBooleanType sharpen, ExceptionInfo* exception)
3250{
3251 MagickBooleanType status;
3252
3253 assert(image != NULL);
3254 assert(exception != NULL);
3255
3256 status = checkOpenCLEnvironment(exception);
3257 if (status == MagickFalse)
3258 return MagickFalse;
3259
dirk5dcb7622013-12-01 10:43:43 +00003260 status = checkAccelerateCondition(image, AllChannels);
cristyf034abb2013-11-24 14:16:14 +00003261 if (status == MagickFalse)
3262 return MagickFalse;
3263
3264 status = ComputeContrastImage(image,sharpen,exception);
cristyf034abb2013-11-24 14:16:14 +00003265 return status;
3266}
3267
3268
3269
3270MagickBooleanType ComputeModulateImage(Image* image, double percent_brightness, double percent_hue, double percent_saturation, ColorspaceType colorspace, ExceptionInfo* exception)
3271{
3272 register ssize_t
cristyd43a46b2010-01-21 02:13:41 +00003273 i;
3274
cristyf034abb2013-11-24 14:16:14 +00003275 cl_float
3276 bright,
3277 hue,
3278 saturation;
3279
3280 cl_int color;
3281
3282 MagickBooleanType outputReady;
3283
3284 MagickCLEnv clEnv;
3285
3286 void *inputPixels;
3287
3288 MagickSizeType length;
3289
3290 cl_context context;
3291 cl_command_queue queue;
3292 cl_kernel modulateKernel;
3293
3294 cl_mem inputImageBuffer;
3295 cl_mem_flags mem_flags;
3296
3297 cl_int clStatus;
3298
3299 Image * inputImage = image;
3300
cristy0c832c62014-03-07 22:21:04 +00003301 inputPixels = NULL;
cristyf034abb2013-11-24 14:16:14 +00003302 inputImageBuffer = NULL;
3303 modulateKernel = NULL;
3304
3305 assert(inputImage != (Image *) NULL);
3306 assert(inputImage->signature == MagickSignature);
3307 if (inputImage->debug != MagickFalse)
3308 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",inputImage->filename);
cristyd43a46b2010-01-21 02:13:41 +00003309
3310 /*
cristyf034abb2013-11-24 14:16:14 +00003311 * initialize opencl env
3312 */
3313 clEnv = GetDefaultOpenCLEnv();
3314 context = GetOpenCLContext(clEnv);
3315 queue = AcquireOpenCLCommandQueue(clEnv);
cristyd43a46b2010-01-21 02:13:41 +00003316
cristyf034abb2013-11-24 14:16:14 +00003317 outputReady = MagickFalse;
cristyd43a46b2010-01-21 02:13:41 +00003318
cristyf034abb2013-11-24 14:16:14 +00003319 /* Create and initialize OpenCL buffers.
3320 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
3321 assume this will get a writable image
3322 */
3323 inputPixels = GetPixelCachePixels(inputImage, &length, exception);
3324 if (inputPixels == (void *) NULL)
cristyd43a46b2010-01-21 02:13:41 +00003325 {
cristya22457d2013-12-07 14:03:06 +00003326 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
cristyf034abb2013-11-24 14:16:14 +00003327 goto cleanup;
cristyd43a46b2010-01-21 02:13:41 +00003328 }
cristyf034abb2013-11-24 14:16:14 +00003329
3330 /* If the host pointer is aligned to the size of CLPixelPacket,
3331 then use the host buffer directly from the GPU; otherwise,
3332 create a buffer on the GPU and copy the data over
3333 */
3334 if (ALIGNED(inputPixels,CLPixelPacket))
3335 {
3336 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
3337 }
3338 else
3339 {
3340 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
3341 }
3342 /* create a CL buffer from image pixel buffer */
3343 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00003344 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00003345 if (clStatus != CL_SUCCESS)
3346 {
cristy0c832c62014-03-07 22:21:04 +00003347 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00003348 goto cleanup;
3349 }
3350
3351 modulateKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Modulate");
3352 if (modulateKernel == NULL)
3353 {
cristya22457d2013-12-07 14:03:06 +00003354 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003355 goto cleanup;
3356 }
3357
3358 bright=percent_brightness;
3359 hue=percent_hue;
3360 saturation=percent_saturation;
3361 color=colorspace;
3362
3363 i = 0;
cristy0c832c62014-03-07 22:21:04 +00003364 clStatus=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
3365 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&bright);
3366 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&hue);
3367 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&saturation);
3368 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&color);
cristyf034abb2013-11-24 14:16:14 +00003369 if (clStatus != CL_SUCCESS)
3370 {
cristy0c832c62014-03-07 22:21:04 +00003371 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003372 printf("no kernel\n");
3373 goto cleanup;
3374 }
3375
3376 {
3377 size_t global_work_size[2];
3378 global_work_size[0] = inputImage->columns;
3379 global_work_size[1] = inputImage->rows;
3380 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00003381 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, modulateKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00003382 if (clStatus != CL_SUCCESS)
3383 {
cristy0c832c62014-03-07 22:21:04 +00003384 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003385 goto cleanup;
3386 }
cristy0c832c62014-03-07 22:21:04 +00003387 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00003388 }
3389
3390 if (ALIGNED(inputPixels,CLPixelPacket))
3391 {
3392 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00003393 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00003394 }
3395 else
3396 {
3397 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00003398 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00003399 }
3400 if (clStatus != CL_SUCCESS)
3401 {
cristya22457d2013-12-07 14:03:06 +00003402 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003403 goto cleanup;
3404 }
3405
3406 outputReady = MagickTrue;
3407
3408cleanup:
cristya22457d2013-12-07 14:03:06 +00003409 OpenCLLogException(__FUNCTION__,__LINE__,exception);
cristyf034abb2013-11-24 14:16:14 +00003410
3411 if (inputPixels) {
3412 //ReleasePixelCachePixels();
3413 inputPixels = NULL;
3414 }
3415
3416 if (inputImageBuffer!=NULL)
cristy0c832c62014-03-07 22:21:04 +00003417 clEnv->library->clReleaseMemObject(inputImageBuffer);
cristyf034abb2013-11-24 14:16:14 +00003418 if (modulateKernel!=NULL)
3419 RelinquishOpenCLKernel(clEnv, modulateKernel);
3420 if (queue != NULL)
3421 RelinquishOpenCLCommandQueue(clEnv, queue);
3422
3423 return outputReady;
3424
cristy3f6d1482010-01-20 21:01:21 +00003425}
cristyf034abb2013-11-24 14:16:14 +00003426
3427/*
3428%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3429% %
3430% %
3431% %
3432% M o d u l a t e I m a g e w i t h O p e n C L %
3433% %
3434% %
3435% %
3436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3437%
3438% ModulateImage() lets you control the brightness, saturation, and hue
3439% of an image. Modulate represents the brightness, saturation, and hue
3440% as one parameter (e.g. 90,150,100). If the image colorspace is HSL, the
3441% modulation is lightness, saturation, and hue. For HWB, use blackness,
3442% whiteness, and hue. And for HCL, use chrome, luma, and hue.
3443%
3444% The format of the ModulateImage method is:
3445%
3446% MagickBooleanType ModulateImage(Image *image,const char *modulate)
3447%
3448% A description of each parameter follows:
3449%
3450% o image: the image.
3451%
3452% o percent_*: Define the percent change in brightness, saturation, and
3453% hue.
3454%
3455*/
3456
3457MagickExport
3458MagickBooleanType AccelerateModulateImage(Image* image, double percent_brightness, double percent_hue, double percent_saturation, ColorspaceType colorspace, ExceptionInfo* exception)
3459{
3460 MagickBooleanType status;
3461
3462 assert(image != NULL);
3463 assert(exception != NULL);
3464
3465 status = checkOpenCLEnvironment(exception);
3466 if (status == MagickFalse)
3467 return MagickFalse;
3468
dirk5dcb7622013-12-01 10:43:43 +00003469 status = checkAccelerateCondition(image, AllChannels);
cristyf034abb2013-11-24 14:16:14 +00003470 if (status == MagickFalse)
3471 return MagickFalse;
3472
3473 if ((colorspace != HSLColorspace && colorspace != UndefinedColorspace))
3474 return MagickFalse;
3475
3476
3477 status = ComputeModulateImage(image,percent_brightness, percent_hue, percent_saturation, colorspace, exception);
cristyf034abb2013-11-24 14:16:14 +00003478 return status;
3479}
3480
cristy0c832c62014-03-07 22:21:04 +00003481MagickBooleanType ComputeNegateImageChannel(Image* image, const ChannelType channel, const MagickBooleanType magick_unused(grayscale), ExceptionInfo* exception)
3482{
3483 register ssize_t
3484 i;
3485
3486 MagickBooleanType outputReady;
3487
3488 MagickCLEnv clEnv;
3489
3490 void *inputPixels;
3491
3492 MagickSizeType length;
3493
3494 cl_context context;
3495 cl_command_queue queue;
3496 cl_kernel negateKernel;
3497
3498 cl_mem inputImageBuffer;
3499 cl_mem_flags mem_flags;
3500
3501 cl_int clStatus;
3502
3503 Image * inputImage = image;
3504
3505 magick_unreferenced(grayscale);
3506
3507 inputPixels = NULL;
3508 inputImageBuffer = NULL;
3509 negateKernel = NULL;
3510
3511 assert(inputImage != (Image *) NULL);
3512 assert(inputImage->signature == MagickSignature);
3513 if (inputImage->debug != MagickFalse)
3514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",inputImage->filename);
3515
3516 /*
3517 * initialize opencl env
3518 */
3519 clEnv = GetDefaultOpenCLEnv();
3520 context = GetOpenCLContext(clEnv);
3521 queue = AcquireOpenCLCommandQueue(clEnv);
3522
3523 outputReady = MagickFalse;
3524
3525 /* Create and initialize OpenCL buffers.
3526 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
3527 assume this will get a writable image
3528 */
3529 inputPixels = GetPixelCachePixels(inputImage, &length, exception);
3530 if (inputPixels == (void *) NULL)
3531 {
3532 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
3533 goto cleanup;
3534 }
3535
3536 /* If the host pointer is aligned to the size of CLPixelPacket,
3537 then use the host buffer directly from the GPU; otherwise,
3538 create a buffer on the GPU and copy the data over
3539 */
3540 if (ALIGNED(inputPixels,CLPixelPacket))
3541 {
3542 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
3543 }
3544 else
3545 {
3546 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
3547 }
3548 /* create a CL buffer from image pixel buffer */
3549 length = inputImage->columns * inputImage->rows;
3550 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
3551 if (clStatus != CL_SUCCESS)
3552 {
3553 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
3554 goto cleanup;
3555 }
3556
3557 negateKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Negate");
3558 if (negateKernel == NULL)
3559 {
3560 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
3561 goto cleanup;
3562 }
3563
3564 i = 0;
3565 clStatus=clEnv->library->clSetKernelArg(negateKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
3566 clStatus=clEnv->library->clSetKernelArg(negateKernel,i++,sizeof(ChannelType),(void *)&channel);
3567 if (clStatus != CL_SUCCESS)
3568 {
3569 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
3570 printf("no kernel\n");
3571 goto cleanup;
3572 }
3573
3574 {
3575 size_t global_work_size[2];
3576 global_work_size[0] = inputImage->columns;
3577 global_work_size[1] = inputImage->rows;
3578 /* launch the kernel */
3579 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, negateKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
3580 if (clStatus != CL_SUCCESS)
3581 {
3582 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
3583 goto cleanup;
3584 }
3585 clEnv->library->clFlush(queue);
3586 }
3587
3588 if (ALIGNED(inputPixels,CLPixelPacket))
3589 {
3590 length = inputImage->columns * inputImage->rows;
3591 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
3592 }
3593 else
3594 {
3595 length = inputImage->columns * inputImage->rows;
3596 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
3597 }
3598 if (clStatus != CL_SUCCESS)
3599 {
3600 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
3601 goto cleanup;
3602 }
3603
3604 outputReady = MagickTrue;
3605
3606cleanup:
3607 OpenCLLogException(__FUNCTION__,__LINE__,exception);
3608
3609 if (inputPixels) {
3610 //ReleasePixelCachePixels();
3611 inputPixels = NULL;
3612 }
3613
3614 if (inputImageBuffer!=NULL)
3615 clEnv->library->clReleaseMemObject(inputImageBuffer);
3616 if (negateKernel!=NULL)
3617 RelinquishOpenCLKernel(clEnv, negateKernel);
3618 if (queue != NULL)
3619 RelinquishOpenCLCommandQueue(clEnv, queue);
3620
3621 return outputReady;
3622
3623}
3624
3625
3626/*
3627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3628% %
3629% %
3630% %
3631% N e g a t e I m a g e w i t h O p e n C L %
3632% %
3633% %
3634% %
3635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3636%
3637%
3638% A description of each parameter follows:
3639%
3640% o image: the image.
3641%
3642% o channel: the channel.
3643%
3644% o grayscale: If MagickTrue, only negate grayscale pixels within the image.
3645%
3646*/
3647
3648MagickExport
3649MagickBooleanType AccelerateNegateImageChannel(Image* image, const ChannelType channel, const MagickBooleanType grayscale, ExceptionInfo* exception)
3650{
3651 MagickBooleanType status;
3652
3653 assert(image != NULL);
3654 assert(exception != NULL);
3655
3656 status = checkOpenCLEnvironment(exception);
3657 if (status == MagickFalse)
3658 return MagickFalse;
3659
3660 status = checkAccelerateCondition(image, AllChannels);
3661 if (status == MagickFalse)
3662 return MagickFalse;
3663
3664 status = ComputeNegateImageChannel(image,channel,grayscale,exception);
3665
3666 return status;
3667}
3668
3669
3670MagickBooleanType ComputeGrayscaleImage(Image* image, const PixelIntensityMethod method, ExceptionInfo* exception)
3671{
3672 register ssize_t
3673 i;
3674
3675 cl_int intensityMethod;
3676 cl_int colorspace;
3677
3678 MagickBooleanType outputReady;
3679
3680 MagickCLEnv clEnv;
3681
3682 void *inputPixels;
3683
3684 MagickSizeType length;
3685
3686 cl_context context;
3687 cl_command_queue queue;
3688 cl_kernel grayscaleKernel;
3689
3690 cl_mem inputImageBuffer;
3691 cl_mem_flags mem_flags;
3692
3693 cl_int clStatus;
3694
3695 Image * inputImage = image;
3696
3697 inputPixels = NULL;
3698 inputImageBuffer = NULL;
3699 grayscaleKernel = NULL;
3700
3701 assert(inputImage != (Image *) NULL);
3702 assert(inputImage->signature == MagickSignature);
3703 if (inputImage->debug != MagickFalse)
3704 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",inputImage->filename);
3705
3706 /*
3707 * initialize opencl env
3708 */
3709 clEnv = GetDefaultOpenCLEnv();
3710 context = GetOpenCLContext(clEnv);
3711 queue = AcquireOpenCLCommandQueue(clEnv);
3712
3713 outputReady = MagickFalse;
3714
3715 /* Create and initialize OpenCL buffers.
3716 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
3717 assume this will get a writable image
3718 */
3719 inputPixels = GetPixelCachePixels(inputImage, &length, exception);
3720 if (inputPixels == (void *) NULL)
3721 {
3722 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
3723 goto cleanup;
3724 }
3725
3726 /* If the host pointer is aligned to the size of CLPixelPacket,
3727 then use the host buffer directly from the GPU; otherwise,
3728 create a buffer on the GPU and copy the data over
3729 */
3730 if (ALIGNED(inputPixels,CLPixelPacket))
3731 {
3732 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
3733 }
3734 else
3735 {
3736 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
3737 }
3738 /* create a CL buffer from image pixel buffer */
3739 length = inputImage->columns * inputImage->rows;
3740 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
3741 if (clStatus != CL_SUCCESS)
3742 {
3743 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
3744 goto cleanup;
3745 }
3746
3747 intensityMethod = method;
3748 colorspace = image->colorspace;
3749
3750 grayscaleKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Grayscale");
3751 if (grayscaleKernel == NULL)
3752 {
3753 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
3754 goto cleanup;
3755 }
3756
3757 i = 0;
3758 clStatus=clEnv->library->clSetKernelArg(grayscaleKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
3759 clStatus|=clEnv->library->clSetKernelArg(grayscaleKernel,i++,sizeof(cl_int),&intensityMethod);
3760 clStatus|=clEnv->library->clSetKernelArg(grayscaleKernel,i++,sizeof(cl_int),&colorspace);
3761 if (clStatus != CL_SUCCESS)
3762 {
3763 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
3764 printf("no kernel\n");
3765 goto cleanup;
3766 }
3767
3768 {
3769 size_t global_work_size[2];
3770 global_work_size[0] = inputImage->columns;
3771 global_work_size[1] = inputImage->rows;
3772 /* launch the kernel */
3773 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, grayscaleKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
3774 if (clStatus != CL_SUCCESS)
3775 {
3776 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
3777 goto cleanup;
3778 }
3779 clEnv->library->clFlush(queue);
3780 }
3781
3782 if (ALIGNED(inputPixels,CLPixelPacket))
3783 {
3784 length = inputImage->columns * inputImage->rows;
3785 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
3786 }
3787 else
3788 {
3789 length = inputImage->columns * inputImage->rows;
3790 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
3791 }
3792 if (clStatus != CL_SUCCESS)
3793 {
3794 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
3795 goto cleanup;
3796 }
3797
3798 outputReady = MagickTrue;
3799
3800cleanup:
3801 OpenCLLogException(__FUNCTION__,__LINE__,exception);
3802
3803 if (inputPixels) {
3804 //ReleasePixelCachePixels();
3805 inputPixels = NULL;
3806 }
3807
3808 if (inputImageBuffer!=NULL)
3809 clEnv->library->clReleaseMemObject(inputImageBuffer);
3810 if (grayscaleKernel!=NULL)
3811 RelinquishOpenCLKernel(clEnv, grayscaleKernel);
3812 if (queue != NULL)
3813 RelinquishOpenCLCommandQueue(clEnv, queue);
3814
3815 return outputReady;
3816
3817}
3818/*
3819%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3820% %
3821% %
3822% %
3823% G r a y s c a l e I m a g e w i t h O p e n C L %
3824% %
3825% %
3826% %
3827%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3828%
3829% GrayscaleImage() converts the colors in the reference image to gray.
3830%
3831% The format of the GrayscaleImageChannel method is:
3832%
3833% MagickBooleanType GrayscaleImage(Image *image,
3834% const PixelIntensityMethod method)
3835%
3836% A description of each parameter follows:
3837%
3838% o image: the image.
3839%
3840% o channel: the channel.
3841%
3842*/
3843
3844MagickExport
3845MagickBooleanType AccelerateGrayscaleImage(Image* image, const PixelIntensityMethod method, ExceptionInfo* exception)
3846{
3847 MagickBooleanType status;
3848
3849 assert(image != NULL);
3850 assert(exception != NULL);
3851
3852 status = checkOpenCLEnvironment(exception);
3853 if (status == MagickFalse)
3854 return MagickFalse;
3855
3856 status = checkAccelerateCondition(image, AllChannels);
3857 if (status == MagickFalse)
3858 return MagickFalse;
3859
3860 if (method == Rec601LuminancePixelIntensityMethod || method == Rec709LuminancePixelIntensityMethod)
3861 return MagickFalse;
3862
3863 if (image->colorspace != sRGBColorspace)
3864 return MagickFalse;
3865
3866 status = ComputeGrayscaleImage(image,method,exception);
3867
3868 return status;
3869}
3870
3871static MagickBooleanType LaunchHistogramKernel(MagickCLEnv clEnv,
3872 cl_command_queue queue,
3873 cl_mem inputImageBuffer,
3874 cl_mem histogramBuffer,
3875 Image *inputImage,
3876 const ChannelType channel,
3877 ExceptionInfo * _exception)
3878{
3879 ExceptionInfo
3880 *exception=_exception;
3881
3882 register ssize_t
3883 i;
3884
3885 MagickBooleanType outputReady;
3886
3887 cl_int clStatus;
3888
3889 size_t global_work_size[2];
3890
3891 cl_kernel histogramKernel;
3892
3893 cl_int method;
3894 cl_int colorspace;
3895
3896 histogramKernel = NULL;
3897
3898 outputReady = MagickFalse;
3899 method = inputImage->intensity;
3900 colorspace = inputImage->colorspace;
3901
3902 /* get the OpenCL kernel */
3903 histogramKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Histogram");
3904 if (histogramKernel == NULL)
3905 {
3906 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
3907 goto cleanup;
3908 }
3909
3910 /* set the kernel arguments */
3911 i = 0;
3912 clStatus=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
3913 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(ChannelType),&channel);
3914 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_int),&method);
3915 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_int),&colorspace);
3916 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_mem),(void *)&histogramBuffer);
3917 if (clStatus != CL_SUCCESS)
3918 {
3919 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
3920 goto cleanup;
3921 }
3922
3923 /* launch the kernel */
3924 global_work_size[0] = inputImage->columns;
3925 global_work_size[1] = inputImage->rows;
3926
3927 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, histogramKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
3928
3929 if (clStatus != CL_SUCCESS)
3930 {
3931 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
3932 goto cleanup;
3933 }
3934 clEnv->library->clFlush(queue);
3935
3936 outputReady = MagickTrue;
3937
3938cleanup:
3939 OpenCLLogException(__FUNCTION__,__LINE__,exception);
3940
3941 if (histogramKernel!=NULL)
3942 RelinquishOpenCLKernel(clEnv, histogramKernel);
3943
3944 return outputReady;
3945}
3946
cristyf034abb2013-11-24 14:16:14 +00003947
3948MagickExport MagickBooleanType ComputeEqualizeImage(Image *inputImage, const ChannelType channel, ExceptionInfo * _exception)
3949{
3950#define EqualizeImageTag "Equalize/Image"
3951
3952 ExceptionInfo
3953 *exception=_exception;
3954
3955 FloatPixelPacket
3956 white,
3957 black,
3958 intensity,
cristy0c832c62014-03-07 22:21:04 +00003959 *map=NULL;
cristyf034abb2013-11-24 14:16:14 +00003960
3961 cl_uint4
cristy0c832c62014-03-07 22:21:04 +00003962 *histogram=NULL;
cristyf034abb2013-11-24 14:16:14 +00003963
3964 PixelPacket
cristy0c832c62014-03-07 22:21:04 +00003965 *equalize_map=NULL;
cristyf034abb2013-11-24 14:16:14 +00003966
3967 register ssize_t
3968 i;
3969
3970 Image * image = inputImage;
3971
3972 MagickBooleanType outputReady;
cristy0c832c62014-03-07 22:21:04 +00003973
cristyf034abb2013-11-24 14:16:14 +00003974 MagickCLEnv clEnv;
3975
3976 cl_int clStatus;
cristy0c832c62014-03-07 22:21:04 +00003977 MagickBooleanType status;
3978
cristyf034abb2013-11-24 14:16:14 +00003979 size_t global_work_size[2];
3980
3981 void *inputPixels;
3982 cl_mem_flags mem_flags;
3983
3984 cl_context context;
3985 cl_mem inputImageBuffer;
3986 cl_mem histogramBuffer;
3987 cl_mem equalizeMapBuffer;
3988 cl_kernel histogramKernel;
3989 cl_kernel equalizeKernel;
3990 cl_command_queue queue;
cristyf034abb2013-11-24 14:16:14 +00003991
3992 void* hostPtr;
3993
3994 MagickSizeType length;
3995
3996 inputPixels = NULL;
3997 inputImageBuffer = NULL;
3998 histogramBuffer = NULL;
cristy0c832c62014-03-07 22:21:04 +00003999 equalizeMapBuffer = NULL;
cristyf034abb2013-11-24 14:16:14 +00004000 histogramKernel = NULL;
4001 equalizeKernel = NULL;
4002 context = NULL;
4003 queue = NULL;
4004 outputReady = MagickFalse;
4005
4006 assert(inputImage != (Image *) NULL);
4007 assert(inputImage->signature == MagickSignature);
4008 if (inputImage->debug != MagickFalse)
4009 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",inputImage->filename);
4010
4011 /*
cristy0c832c62014-03-07 22:21:04 +00004012 * initialize opencl env
4013 */
4014 clEnv = GetDefaultOpenCLEnv();
4015 context = GetOpenCLContext(clEnv);
4016 queue = AcquireOpenCLCommandQueue(clEnv);
4017
4018 /*
cristyf034abb2013-11-24 14:16:14 +00004019 Allocate and initialize histogram arrays.
4020 */
4021 histogram=(cl_uint4 *) AcquireQuantumMemory(MaxMap+1UL, sizeof(*histogram));
4022 if (histogram == (cl_uint4 *) NULL)
4023 ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", image->filename);
4024
4025 /* reset histogram */
4026 (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram));
4027
cristyf034abb2013-11-24 14:16:14 +00004028 /* Create and initialize OpenCL buffers. */
4029 /* inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); */
4030 /* assume this will get a writable image */
4031 inputPixels = GetPixelCachePixels(inputImage, &length, exception);
4032
4033 if (inputPixels == (void *) NULL)
4034 {
cristya22457d2013-12-07 14:03:06 +00004035 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
cristyf034abb2013-11-24 14:16:14 +00004036 goto cleanup;
4037 }
4038 /* If the host pointer is aligned to the size of CLPixelPacket,
4039 then use the host buffer directly from the GPU; otherwise,
4040 create a buffer on the GPU and copy the data over */
4041 if (ALIGNED(inputPixels,CLPixelPacket))
4042 {
4043 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
4044 }
4045 else
4046 {
4047 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
4048 }
4049 /* create a CL buffer from image pixel buffer */
4050 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00004051 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00004052 if (clStatus != CL_SUCCESS)
4053 {
cristy0c832c62014-03-07 22:21:04 +00004054 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00004055 goto cleanup;
4056 }
cristy0c832c62014-03-07 22:21:04 +00004057
cristyf034abb2013-11-24 14:16:14 +00004058 /* If the host pointer is aligned to the size of cl_uint,
4059 then use the host buffer directly from the GPU; otherwise,
4060 create a buffer on the GPU and copy the data over */
4061 if (ALIGNED(histogram,cl_uint4))
4062 {
4063 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
4064 hostPtr = histogram;
4065 }
4066 else
4067 {
4068 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4069 hostPtr = histogram;
4070 }
4071 /* create a CL buffer for histogram */
4072 length = (MaxMap+1);
cristy0c832c62014-03-07 22:21:04 +00004073 histogramBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(cl_uint4), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00004074 if (clStatus != CL_SUCCESS)
4075 {
cristy0c832c62014-03-07 22:21:04 +00004076 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00004077 goto cleanup;
4078 }
4079
cristy0c832c62014-03-07 22:21:04 +00004080 status = LaunchHistogramKernel(clEnv, queue, inputImageBuffer, histogramBuffer, image, channel, exception);
4081 if (status == MagickFalse)
cristyf034abb2013-11-24 14:16:14 +00004082 goto cleanup;
cristyf034abb2013-11-24 14:16:14 +00004083
4084 /* read from the kenel output */
4085 if (ALIGNED(histogram,cl_uint4))
4086 {
4087 length = (MaxMap+1);
cristy0c832c62014-03-07 22:21:04 +00004088 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 +00004089 }
4090 else
4091 {
4092 length = (MaxMap+1);
cristy0c832c62014-03-07 22:21:04 +00004093 clStatus = clEnv->library->clEnqueueReadBuffer(queue, histogramBuffer, CL_TRUE, 0, length * sizeof(cl_uint4), histogram, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00004094 }
4095 if (clStatus != CL_SUCCESS)
4096 {
cristya22457d2013-12-07 14:03:06 +00004097 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00004098 goto cleanup;
4099 }
4100
4101 /* unmap, don't block gpu to use this buffer again. */
4102 if (ALIGNED(histogram,cl_uint4))
4103 {
cristy0c832c62014-03-07 22:21:04 +00004104 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, histogramBuffer, histogram, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00004105 if (clStatus != CL_SUCCESS)
4106 {
cristy0c832c62014-03-07 22:21:04 +00004107 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00004108 goto cleanup;
4109 }
4110 }
4111
cristy0c832c62014-03-07 22:21:04 +00004112 /* recreate input buffer later, in case image updated */
4113#ifdef RECREATEBUFFER
4114 if (inputImageBuffer!=NULL)
4115 clEnv->library->clReleaseMemObject(inputImageBuffer);
4116#endif
4117
4118 /* CPU stuff */
cristyf034abb2013-11-24 14:16:14 +00004119 equalize_map=(PixelPacket *) AcquireQuantumMemory(MaxMap+1UL, sizeof(*equalize_map));
4120 if (equalize_map == (PixelPacket *) NULL)
cristy0c832c62014-03-07 22:21:04 +00004121 ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", image->filename);
cristyf034abb2013-11-24 14:16:14 +00004122
4123 map=(FloatPixelPacket *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*map));
4124 if (map == (FloatPixelPacket *) NULL)
cristy0c832c62014-03-07 22:21:04 +00004125 ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", image->filename);
cristyf034abb2013-11-24 14:16:14 +00004126
4127 /*
4128 Integrate the histogram to get the equalization map.
4129 */
4130 (void) ResetMagickMemory(&intensity,0,sizeof(intensity));
4131 for (i=0; i <= (ssize_t) MaxMap; i++)
4132 {
4133 if ((channel & SyncChannels) != 0)
cristy0c832c62014-03-07 22:21:04 +00004134 {
4135 intensity.red+=histogram[i].s[2];
4136 map[i]=intensity;
4137 continue;
4138 }
cristyf034abb2013-11-24 14:16:14 +00004139 if ((channel & RedChannel) != 0)
4140 intensity.red+=histogram[i].s[2];
4141 if ((channel & GreenChannel) != 0)
4142 intensity.green+=histogram[i].s[1];
4143 if ((channel & BlueChannel) != 0)
4144 intensity.blue+=histogram[i].s[0];
4145 if ((channel & OpacityChannel) != 0)
cristy0c832c62014-03-07 22:21:04 +00004146 intensity.opacity+=histogram[i].s[3];
4147 /*
cristyf034abb2013-11-24 14:16:14 +00004148 if (((channel & IndexChannel) != 0) &&
4149 (image->colorspace == CMYKColorspace))
4150 {
cristy0c832c62014-03-07 22:21:04 +00004151 intensity.index+=histogram[i].index;
cristyf034abb2013-11-24 14:16:14 +00004152 }
cristy0c832c62014-03-07 22:21:04 +00004153 */
cristyf034abb2013-11-24 14:16:14 +00004154 map[i]=intensity;
4155 }
4156 black=map[0];
4157 white=map[(int) MaxMap];
4158 (void) ResetMagickMemory(equalize_map,0,(MaxMap+1)*sizeof(*equalize_map));
4159 for (i=0; i <= (ssize_t) MaxMap; i++)
4160 {
4161 if ((channel & SyncChannels) != 0)
cristy0c832c62014-03-07 22:21:04 +00004162 {
4163 if (white.red != black.red)
4164 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
4165 (map[i].red-black.red))/(white.red-black.red)));
4166 continue;
4167 }
cristyf034abb2013-11-24 14:16:14 +00004168 if (((channel & RedChannel) != 0) && (white.red != black.red))
4169 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
cristy0c832c62014-03-07 22:21:04 +00004170 (map[i].red-black.red))/(white.red-black.red)));
cristyf034abb2013-11-24 14:16:14 +00004171 if (((channel & GreenChannel) != 0) && (white.green != black.green))
4172 equalize_map[i].green=ScaleMapToQuantum((MagickRealType) ((MaxMap*
cristy0c832c62014-03-07 22:21:04 +00004173 (map[i].green-black.green))/(white.green-black.green)));
cristyf034abb2013-11-24 14:16:14 +00004174 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
4175 equalize_map[i].blue=ScaleMapToQuantum((MagickRealType) ((MaxMap*
cristy0c832c62014-03-07 22:21:04 +00004176 (map[i].blue-black.blue))/(white.blue-black.blue)));
4177 if (((channel & OpacityChannel) != 0) && (white.opacity != black.opacity))
4178 equalize_map[i].opacity=ScaleMapToQuantum((MagickRealType) ((MaxMap*
4179 (map[i].opacity-black.opacity))/(white.opacity-black.opacity)));
cristyf034abb2013-11-24 14:16:14 +00004180 /*
4181 if ((((channel & IndexChannel) != 0) &&
cristy0c832c62014-03-07 22:21:04 +00004182 (image->colorspace == CMYKColorspace)) &&
cristyf034abb2013-11-24 14:16:14 +00004183 (white.index != black.index))
4184 equalize_map[i].index=ScaleMapToQuantum((MagickRealType) ((MaxMap*
cristy0c832c62014-03-07 22:21:04 +00004185 (map[i].index-black.index))/(white.index-black.index)));
cristyf034abb2013-11-24 14:16:14 +00004186 */
4187 }
4188
cristyf034abb2013-11-24 14:16:14 +00004189 if (image->storage_class == PseudoClass)
4190 {
cristy0c832c62014-03-07 22:21:04 +00004191 /*
4192 Equalize colormap.
4193 */
4194 for (i=0; i < (ssize_t) image->colors; i++)
4195 {
4196 if ((channel & SyncChannels) != 0)
cristyf034abb2013-11-24 14:16:14 +00004197 {
cristy0c832c62014-03-07 22:21:04 +00004198 if (white.red != black.red)
4199 {
cristyf034abb2013-11-24 14:16:14 +00004200 image->colormap[i].red=equalize_map[
4201 ScaleQuantumToMap(image->colormap[i].red)].red;
cristyf034abb2013-11-24 14:16:14 +00004202 image->colormap[i].green=equalize_map[
cristy0c832c62014-03-07 22:21:04 +00004203 ScaleQuantumToMap(image->colormap[i].green)].red;
cristyf034abb2013-11-24 14:16:14 +00004204 image->colormap[i].blue=equalize_map[
cristy0c832c62014-03-07 22:21:04 +00004205 ScaleQuantumToMap(image->colormap[i].blue)].red;
4206 image->colormap[i].opacity=equalize_map[
4207 ScaleQuantumToMap(image->colormap[i].opacity)].red;
4208 }
4209 continue;
cristyf034abb2013-11-24 14:16:14 +00004210 }
cristy0c832c62014-03-07 22:21:04 +00004211 if (((channel & RedChannel) != 0) && (white.red != black.red))
4212 image->colormap[i].red=equalize_map[
4213 ScaleQuantumToMap(image->colormap[i].red)].red;
4214 if (((channel & GreenChannel) != 0) && (white.green != black.green))
4215 image->colormap[i].green=equalize_map[
4216 ScaleQuantumToMap(image->colormap[i].green)].green;
4217 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
4218 image->colormap[i].blue=equalize_map[
4219 ScaleQuantumToMap(image->colormap[i].blue)].blue;
4220 if (((channel & OpacityChannel) != 0) &&
4221 (white.opacity != black.opacity))
4222 image->colormap[i].opacity=equalize_map[
4223 ScaleQuantumToMap(image->colormap[i].opacity)].opacity;
4224 }
cristyf034abb2013-11-24 14:16:14 +00004225 }
4226
4227 /*
4228 Equalize image.
4229 */
4230
4231 /* GPU can work on this again, image and equalize map as input
4232 image: uchar4 (CLPixelPacket)
4233 equalize_map: uchar4 (PixelPacket)
4234 black, white: float4 (FloatPixelPacket) */
4235
cristy0c832c62014-03-07 22:21:04 +00004236#ifdef RECREATEBUFFER
cristyf034abb2013-11-24 14:16:14 +00004237 /* If the host pointer is aligned to the size of CLPixelPacket,
4238 then use the host buffer directly from the GPU; otherwise,
4239 create a buffer on the GPU and copy the data over */
4240 if (ALIGNED(inputPixels,CLPixelPacket))
4241 {
4242 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
4243 }
4244 else
4245 {
4246 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4247 }
4248 /* create a CL buffer from image pixel buffer */
4249 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00004250 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00004251 if (clStatus != CL_SUCCESS)
4252 {
cristy0c832c62014-03-07 22:21:04 +00004253 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00004254 goto cleanup;
4255 }
cristy0c832c62014-03-07 22:21:04 +00004256#endif
cristyf034abb2013-11-24 14:16:14 +00004257
4258 /* Create and initialize OpenCL buffers. */
4259 if (ALIGNED(equalize_map, PixelPacket))
4260 {
4261 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
4262 hostPtr = equalize_map;
4263 }
4264 else
4265 {
4266 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4267 hostPtr = equalize_map;
4268 }
4269 /* create a CL buffer for eqaulize_map */
4270 length = (MaxMap+1);
cristy0c832c62014-03-07 22:21:04 +00004271 equalizeMapBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(PixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00004272 if (clStatus != CL_SUCCESS)
4273 {
cristy0c832c62014-03-07 22:21:04 +00004274 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00004275 goto cleanup;
4276 }
4277
4278 /* get the OpenCL kernel */
4279 equalizeKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Equalize");
4280 if (equalizeKernel == NULL)
4281 {
cristya22457d2013-12-07 14:03:06 +00004282 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00004283 goto cleanup;
4284 }
4285
4286 /* set the kernel arguments */
4287 i = 0;
cristy0c832c62014-03-07 22:21:04 +00004288 clStatus=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
4289 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(ChannelType),&channel);
4290 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(cl_mem),(void *)&equalizeMapBuffer);
4291 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(FloatPixelPacket),&white);
4292 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(FloatPixelPacket),&black);
cristyf034abb2013-11-24 14:16:14 +00004293 if (clStatus != CL_SUCCESS)
4294 {
cristy0c832c62014-03-07 22:21:04 +00004295 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00004296 goto cleanup;
4297 }
4298
4299 /* launch the kernel */
4300 global_work_size[0] = inputImage->columns;
4301 global_work_size[1] = inputImage->rows;
4302
cristy0c832c62014-03-07 22:21:04 +00004303 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, equalizeKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00004304
4305 if (clStatus != CL_SUCCESS)
4306 {
cristy0c832c62014-03-07 22:21:04 +00004307 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00004308 goto cleanup;
4309 }
cristy0c832c62014-03-07 22:21:04 +00004310 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00004311
4312 /* read the data back */
4313 if (ALIGNED(inputPixels,CLPixelPacket))
4314 {
4315 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00004316 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00004317 }
4318 else
4319 {
4320 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00004321 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00004322 }
4323 if (clStatus != CL_SUCCESS)
4324 {
cristya22457d2013-12-07 14:03:06 +00004325 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00004326 goto cleanup;
4327 }
4328
4329 outputReady = MagickTrue;
cristyf034abb2013-11-24 14:16:14 +00004330
4331cleanup:
cristya22457d2013-12-07 14:03:06 +00004332 OpenCLLogException(__FUNCTION__,__LINE__,exception);
cristyf034abb2013-11-24 14:16:14 +00004333
4334 if (inputPixels) {
4335 /*ReleasePixelCachePixels();*/
4336 inputPixels = NULL;
4337 }
4338
4339 if (inputImageBuffer!=NULL)
cristy0c832c62014-03-07 22:21:04 +00004340 clEnv->library->clReleaseMemObject(inputImageBuffer);
4341
4342 if (map!=NULL)
4343 map=(FloatPixelPacket *) RelinquishMagickMemory(map);
4344
4345 if (equalizeMapBuffer!=NULL)
4346 clEnv->library->clReleaseMemObject(equalizeMapBuffer);
4347 if (equalize_map!=NULL)
4348 equalize_map=(PixelPacket *) RelinquishMagickMemory(equalize_map);
4349
cristyf034abb2013-11-24 14:16:14 +00004350 if (histogramBuffer!=NULL)
cristy0c832c62014-03-07 22:21:04 +00004351 clEnv->library->clReleaseMemObject(histogramBuffer);
4352 if (histogram!=NULL)
4353 histogram=(cl_uint4 *) RelinquishMagickMemory(histogram);
4354
cristyf034abb2013-11-24 14:16:14 +00004355 if (histogramKernel!=NULL)
4356 RelinquishOpenCLKernel(clEnv, histogramKernel);
cristy0c832c62014-03-07 22:21:04 +00004357 if (equalizeKernel!=NULL)
4358 RelinquishOpenCLKernel(clEnv, equalizeKernel);
4359
cristyf034abb2013-11-24 14:16:14 +00004360 if (queue != NULL)
4361 RelinquishOpenCLCommandQueue(clEnv, queue);
4362
4363 return outputReady;
4364}
4365
4366/*
4367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4368% %
4369% %
4370% %
4371% E q u a l i z e I m a g e w i t h O p e n C L %
4372% %
4373% %
4374% %
4375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4376%
4377% EqualizeImage() applies a histogram equalization to the image.
4378%
4379% The format of the EqualizeImage method is:
4380%
4381% MagickBooleanType EqualizeImage(Image *image)
4382% MagickBooleanType EqualizeImageChannel(Image *image,
4383% const ChannelType channel)
4384%
4385% A description of each parameter follows:
4386%
4387% o image: the image.
4388%
4389% o channel: the channel.
4390%
4391*/
4392
4393
4394MagickExport
4395MagickBooleanType AccelerateEqualizeImage(Image* image, const ChannelType channel, ExceptionInfo* exception)
4396{
4397 MagickBooleanType status;
4398
4399 assert(image != NULL);
4400 assert(exception != NULL);
4401
4402 status = checkOpenCLEnvironment(exception);
4403 if (status == MagickFalse)
4404 return MagickFalse;
4405
dirk5dcb7622013-12-01 10:43:43 +00004406 status = checkAccelerateCondition(image, channel);
cristyf034abb2013-11-24 14:16:14 +00004407 if (status == MagickFalse)
4408 return MagickFalse;
4409
cristy0c832c62014-03-07 22:21:04 +00004410 status = checkHistogramCondition(image, channel);
4411 if (status == MagickFalse)
cristyf034abb2013-11-24 14:16:14 +00004412 return MagickFalse;
4413
4414 status = ComputeEqualizeImage(image,channel,exception);
cristyf034abb2013-11-24 14:16:14 +00004415 return status;
4416}
4417
4418
cristy0c832c62014-03-07 22:21:04 +00004419
4420MagickExport MagickBooleanType ComputeContrastStretchImageChannel(Image *image,
4421 const ChannelType channel,const double black_point,const double white_point,
4422 ExceptionInfo * _exception)
4423{
4424#define MaxRange(color) ((MagickRealType) ScaleQuantumToMap((Quantum) (color)))
4425#define ContrastStretchImageTag "ContrastStretch/Image"
4426
4427 ExceptionInfo
4428 *exception=_exception;
4429
4430 double
4431 intensity;
4432
4433 FloatPixelPacket
4434 black,
4435 white;
4436
4437 cl_uint4
4438 *histogram=NULL;
4439
4440 PixelPacket
4441 *stretch_map=NULL;
4442
4443 register ssize_t
4444 i;
4445
4446 Image * inputImage;
4447
4448 MagickBooleanType outputReady;
4449
4450 MagickCLEnv clEnv;
4451
4452 cl_int clStatus;
4453 MagickBooleanType status;
4454
4455 size_t global_work_size[2];
4456
4457 void *inputPixels;
4458 cl_mem_flags mem_flags;
4459
4460 cl_context context;
4461 cl_mem inputImageBuffer;
4462 cl_mem histogramBuffer;
4463 cl_mem stretchMapBuffer;
4464 cl_kernel histogramKernel;
4465 cl_kernel stretchKernel;
4466 cl_command_queue queue;
4467
4468 void* hostPtr;
4469
4470 MagickSizeType length;
4471
4472 inputImage = image;
4473 inputPixels = NULL;
4474 inputImageBuffer = NULL;
4475 histogramBuffer = NULL;
4476 stretchMapBuffer = NULL;
4477 histogramKernel = NULL;
4478 stretchKernel = NULL;
4479 context = NULL;
4480 queue = NULL;
4481 outputReady = MagickFalse;
4482
4483
4484 assert(image != (Image *) NULL);
4485 assert(image->signature == MagickSignature);
4486 if (image->debug != MagickFalse)
4487 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4488
4489 //exception=(&image->exception);
4490
4491 /*
4492 * initialize opencl env
4493 */
4494 clEnv = GetDefaultOpenCLEnv();
4495 context = GetOpenCLContext(clEnv);
4496 queue = AcquireOpenCLCommandQueue(clEnv);
4497
4498 /*
4499 Allocate and initialize histogram arrays.
4500 */
4501 histogram=(cl_uint4 *) AcquireQuantumMemory(MaxMap+1UL, sizeof(*histogram));
4502
4503 if ((histogram == (cl_uint4 *) NULL))
4504 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", image->filename);
4505
4506 /* reset histogram */
4507 (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram));
4508
4509 /*
4510 if (IsGrayImage(image,exception) != MagickFalse)
4511 (void) SetImageColorspace(image,GRAYColorspace);
4512 */
4513
4514 status=MagickTrue;
4515
4516
4517 /*
4518 Form histogram.
4519 */
4520 /* Create and initialize OpenCL buffers. */
4521 /* inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); */
4522 /* assume this will get a writable image */
4523 inputPixels = GetPixelCachePixels(inputImage, &length, exception);
4524
4525 if (inputPixels == (void *) NULL)
4526 {
4527 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
4528 goto cleanup;
4529 }
4530 /* If the host pointer is aligned to the size of CLPixelPacket,
4531 then use the host buffer directly from the GPU; otherwise,
4532 create a buffer on the GPU and copy the data over */
4533 if (ALIGNED(inputPixels,CLPixelPacket))
4534 {
4535 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
4536 }
4537 else
4538 {
4539 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
4540 }
4541 /* create a CL buffer from image pixel buffer */
4542 length = inputImage->columns * inputImage->rows;
4543 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
4544 if (clStatus != CL_SUCCESS)
4545 {
4546 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
4547 goto cleanup;
4548 }
4549
4550 /* If the host pointer is aligned to the size of cl_uint,
4551 then use the host buffer directly from the GPU; otherwise,
4552 create a buffer on the GPU and copy the data over */
4553 if (ALIGNED(histogram,cl_uint4))
4554 {
4555 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
4556 hostPtr = histogram;
4557 }
4558 else
4559 {
4560 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4561 hostPtr = histogram;
4562 }
4563 /* create a CL buffer for histogram */
4564 length = (MaxMap+1);
4565 histogramBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(cl_uint4), hostPtr, &clStatus);
4566 if (clStatus != CL_SUCCESS)
4567 {
4568 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
4569 goto cleanup;
4570 }
4571
4572 status = LaunchHistogramKernel(clEnv, queue, inputImageBuffer, histogramBuffer, image, channel, exception);
4573 if (status == MagickFalse)
4574 goto cleanup;
4575
4576 /* read from the kenel output */
4577 if (ALIGNED(histogram,cl_uint4))
4578 {
4579 length = (MaxMap+1);
4580 clEnv->library->clEnqueueMapBuffer(queue, histogramBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(cl_uint4), 0, NULL, NULL, &clStatus);
4581 }
4582 else
4583 {
4584 length = (MaxMap+1);
4585 clStatus = clEnv->library->clEnqueueReadBuffer(queue, histogramBuffer, CL_TRUE, 0, length * sizeof(cl_uint4), histogram, 0, NULL, NULL);
4586 }
4587 if (clStatus != CL_SUCCESS)
4588 {
4589 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
4590 goto cleanup;
4591 }
4592
4593 /* unmap, don't block gpu to use this buffer again. */
4594 if (ALIGNED(histogram,cl_uint4))
4595 {
4596 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, histogramBuffer, histogram, 0, NULL, NULL);
4597 if (clStatus != CL_SUCCESS)
4598 {
4599 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
4600 goto cleanup;
4601 }
4602 }
4603
4604 /* recreate input buffer later, in case image updated */
4605#ifdef RECREATEBUFFER
4606 if (inputImageBuffer!=NULL)
4607 clEnv->library->clReleaseMemObject(inputImageBuffer);
4608#endif
4609
4610 /* CPU stuff */
4611 /*
4612 Find the histogram boundaries by locating the black/white levels.
4613 */
4614 black.red=0.0;
4615 white.red=MaxRange(QuantumRange);
4616 if ((channel & RedChannel) != 0)
4617 {
4618 intensity=0.0;
4619 for (i=0; i <= (ssize_t) MaxMap; i++)
4620 {
4621 intensity+=histogram[i].s[2];
4622 if (intensity > black_point)
4623 break;
4624 }
4625 black.red=(MagickRealType) i;
4626 intensity=0.0;
4627 for (i=(ssize_t) MaxMap; i != 0; i--)
4628 {
4629 intensity+=histogram[i].s[2];
4630 if (intensity > ((double) image->columns*image->rows-white_point))
4631 break;
4632 }
4633 white.red=(MagickRealType) i;
4634 }
4635 black.green=0.0;
4636 white.green=MaxRange(QuantumRange);
4637 if ((channel & GreenChannel) != 0)
4638 {
4639 intensity=0.0;
4640 for (i=0; i <= (ssize_t) MaxMap; i++)
4641 {
4642 intensity+=histogram[i].s[2];
4643 if (intensity > black_point)
4644 break;
4645 }
4646 black.green=(MagickRealType) i;
4647 intensity=0.0;
4648 for (i=(ssize_t) MaxMap; i != 0; i--)
4649 {
4650 intensity+=histogram[i].s[2];
4651 if (intensity > ((double) image->columns*image->rows-white_point))
4652 break;
4653 }
4654 white.green=(MagickRealType) i;
4655 }
4656 black.blue=0.0;
4657 white.blue=MaxRange(QuantumRange);
4658 if ((channel & BlueChannel) != 0)
4659 {
4660 intensity=0.0;
4661 for (i=0; i <= (ssize_t) MaxMap; i++)
4662 {
4663 intensity+=histogram[i].s[2];
4664 if (intensity > black_point)
4665 break;
4666 }
4667 black.blue=(MagickRealType) i;
4668 intensity=0.0;
4669 for (i=(ssize_t) MaxMap; i != 0; i--)
4670 {
4671 intensity+=histogram[i].s[2];
4672 if (intensity > ((double) image->columns*image->rows-white_point))
4673 break;
4674 }
4675 white.blue=(MagickRealType) i;
4676 }
4677 black.opacity=0.0;
4678 white.opacity=MaxRange(QuantumRange);
4679 if ((channel & OpacityChannel) != 0)
4680 {
4681 intensity=0.0;
4682 for (i=0; i <= (ssize_t) MaxMap; i++)
4683 {
4684 intensity+=histogram[i].s[2];
4685 if (intensity > black_point)
4686 break;
4687 }
4688 black.opacity=(MagickRealType) i;
4689 intensity=0.0;
4690 for (i=(ssize_t) MaxMap; i != 0; i--)
4691 {
4692 intensity+=histogram[i].s[2];
4693 if (intensity > ((double) image->columns*image->rows-white_point))
4694 break;
4695 }
4696 white.opacity=(MagickRealType) i;
4697 }
4698 /*
4699 black.index=0.0;
4700 white.index=MaxRange(QuantumRange);
4701 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
4702 {
4703 intensity=0.0;
4704 for (i=0; i <= (ssize_t) MaxMap; i++)
4705 {
4706 intensity+=histogram[i].index;
4707 if (intensity > black_point)
4708 break;
4709 }
4710 black.index=(MagickRealType) i;
4711 intensity=0.0;
4712 for (i=(ssize_t) MaxMap; i != 0; i--)
4713 {
4714 intensity+=histogram[i].index;
4715 if (intensity > ((double) image->columns*image->rows-white_point))
4716 break;
4717 }
4718 white.index=(MagickRealType) i;
4719 }
4720 */
4721
4722
4723 stretch_map=(PixelPacket *) AcquireQuantumMemory(MaxMap+1UL,
4724 sizeof(*stretch_map));
4725
4726 if ((stretch_map == (PixelPacket *) NULL))
4727 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
4728 image->filename);
4729
4730 /*
4731 Stretch the histogram to create the stretched image mapping.
4732 */
4733 (void) ResetMagickMemory(stretch_map,0,(MaxMap+1)*sizeof(*stretch_map));
4734 for (i=0; i <= (ssize_t) MaxMap; i++)
4735 {
4736 if ((channel & RedChannel) != 0)
4737 {
4738 if (i < (ssize_t) black.red)
4739 stretch_map[i].red=(Quantum) 0;
4740 else
4741 if (i > (ssize_t) white.red)
4742 stretch_map[i].red=QuantumRange;
4743 else
4744 if (black.red != white.red)
4745 stretch_map[i].red=ScaleMapToQuantum((MagickRealType) (MaxMap*
4746 (i-black.red)/(white.red-black.red)));
4747 }
4748 if ((channel & GreenChannel) != 0)
4749 {
4750 if (i < (ssize_t) black.green)
4751 stretch_map[i].green=0;
4752 else
4753 if (i > (ssize_t) white.green)
4754 stretch_map[i].green=QuantumRange;
4755 else
4756 if (black.green != white.green)
4757 stretch_map[i].green=ScaleMapToQuantum((MagickRealType) (MaxMap*
4758 (i-black.green)/(white.green-black.green)));
4759 }
4760 if ((channel & BlueChannel) != 0)
4761 {
4762 if (i < (ssize_t) black.blue)
4763 stretch_map[i].blue=0;
4764 else
4765 if (i > (ssize_t) white.blue)
4766 stretch_map[i].blue= QuantumRange;
4767 else
4768 if (black.blue != white.blue)
4769 stretch_map[i].blue=ScaleMapToQuantum((MagickRealType) (MaxMap*
4770 (i-black.blue)/(white.blue-black.blue)));
4771 }
4772 if ((channel & OpacityChannel) != 0)
4773 {
4774 if (i < (ssize_t) black.opacity)
4775 stretch_map[i].opacity=0;
4776 else
4777 if (i > (ssize_t) white.opacity)
4778 stretch_map[i].opacity=QuantumRange;
4779 else
4780 if (black.opacity != white.opacity)
4781 stretch_map[i].opacity=ScaleMapToQuantum((MagickRealType) (MaxMap*
4782 (i-black.opacity)/(white.opacity-black.opacity)));
4783 }
4784 /*
4785 if (((channel & IndexChannel) != 0) &&
4786 (image->colorspace == CMYKColorspace))
4787 {
4788 if (i < (ssize_t) black.index)
4789 stretch_map[i].index=0;
4790 else
4791 if (i > (ssize_t) white.index)
4792 stretch_map[i].index=QuantumRange;
4793 else
4794 if (black.index != white.index)
4795 stretch_map[i].index=ScaleMapToQuantum((MagickRealType) (MaxMap*
4796 (i-black.index)/(white.index-black.index)));
4797 }
4798 */
4799 }
4800
4801 /*
4802 Stretch the image.
4803 */
4804 if (((channel & OpacityChannel) != 0) || (((channel & IndexChannel) != 0) &&
4805 (image->colorspace == CMYKColorspace)))
4806 image->storage_class=DirectClass;
4807 if (image->storage_class == PseudoClass)
4808 {
4809 /*
4810 Stretch colormap.
4811 */
4812 for (i=0; i < (ssize_t) image->colors; i++)
4813 {
4814 if ((channel & RedChannel) != 0)
4815 {
4816 if (black.red != white.red)
4817 image->colormap[i].red=stretch_map[
4818 ScaleQuantumToMap(image->colormap[i].red)].red;
4819 }
4820 if ((channel & GreenChannel) != 0)
4821 {
4822 if (black.green != white.green)
4823 image->colormap[i].green=stretch_map[
4824 ScaleQuantumToMap(image->colormap[i].green)].green;
4825 }
4826 if ((channel & BlueChannel) != 0)
4827 {
4828 if (black.blue != white.blue)
4829 image->colormap[i].blue=stretch_map[
4830 ScaleQuantumToMap(image->colormap[i].blue)].blue;
4831 }
4832 if ((channel & OpacityChannel) != 0)
4833 {
4834 if (black.opacity != white.opacity)
4835 image->colormap[i].opacity=stretch_map[
4836 ScaleQuantumToMap(image->colormap[i].opacity)].opacity;
4837 }
4838 }
4839 }
4840
4841 /*
4842 Stretch image.
4843 */
4844
4845
4846 /* GPU can work on this again, image and equalize map as input
4847 image: uchar4 (CLPixelPacket)
4848 stretch_map: uchar4 (PixelPacket)
4849 black, white: float4 (FloatPixelPacket) */
4850
4851#ifdef RECREATEBUFFER
4852 /* If the host pointer is aligned to the size of CLPixelPacket,
4853 then use the host buffer directly from the GPU; otherwise,
4854 create a buffer on the GPU and copy the data over */
4855 if (ALIGNED(inputPixels,CLPixelPacket))
4856 {
4857 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
4858 }
4859 else
4860 {
4861 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4862 }
4863 /* create a CL buffer from image pixel buffer */
4864 length = inputImage->columns * inputImage->rows;
4865 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
4866 if (clStatus != CL_SUCCESS)
4867 {
4868 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
4869 goto cleanup;
4870 }
4871#endif
4872
4873 /* Create and initialize OpenCL buffers. */
4874 if (ALIGNED(stretch_map, PixelPacket))
4875 {
4876 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
4877 hostPtr = stretch_map;
4878 }
4879 else
4880 {
4881 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4882 hostPtr = stretch_map;
4883 }
4884 /* create a CL buffer for stretch_map */
4885 length = (MaxMap+1);
4886 stretchMapBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(PixelPacket), hostPtr, &clStatus);
4887 if (clStatus != CL_SUCCESS)
4888 {
4889 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
4890 goto cleanup;
4891 }
4892
4893 /* get the OpenCL kernel */
4894 stretchKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Stretch");
4895 if (stretchKernel == NULL)
4896 {
4897 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
4898 goto cleanup;
4899 }
4900
4901 /* set the kernel arguments */
4902 i = 0;
4903 clStatus=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
4904 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(ChannelType),&channel);
4905 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(cl_mem),(void *)&stretchMapBuffer);
4906 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(FloatPixelPacket),&white);
4907 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(FloatPixelPacket),&black);
4908 if (clStatus != CL_SUCCESS)
4909 {
4910 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
4911 goto cleanup;
4912 }
4913
4914 /* launch the kernel */
4915 global_work_size[0] = inputImage->columns;
4916 global_work_size[1] = inputImage->rows;
4917
4918 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, stretchKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
4919
4920 if (clStatus != CL_SUCCESS)
4921 {
4922 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
4923 goto cleanup;
4924 }
4925 clEnv->library->clFlush(queue);
4926
4927 /* read the data back */
4928 if (ALIGNED(inputPixels,CLPixelPacket))
4929 {
4930 length = inputImage->columns * inputImage->rows;
4931 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
4932 }
4933 else
4934 {
4935 length = inputImage->columns * inputImage->rows;
4936 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
4937 }
4938 if (clStatus != CL_SUCCESS)
4939 {
4940 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
4941 goto cleanup;
4942 }
4943
4944 outputReady = MagickTrue;
4945
4946cleanup:
4947 OpenCLLogException(__FUNCTION__,__LINE__,exception);
4948
4949 if (inputPixels) {
4950 /*ReleasePixelCachePixels();*/
4951 inputPixels = NULL;
4952 }
4953
4954 if (inputImageBuffer!=NULL)
4955 clEnv->library->clReleaseMemObject(inputImageBuffer);
4956
4957 if (stretchMapBuffer!=NULL)
4958 clEnv->library->clReleaseMemObject(stretchMapBuffer);
4959 if (stretch_map!=NULL)
4960 stretch_map=(PixelPacket *) RelinquishMagickMemory(stretch_map);
4961
4962
4963 if (histogramBuffer!=NULL)
4964 clEnv->library->clReleaseMemObject(histogramBuffer);
4965 if (histogram!=NULL)
4966 histogram=(cl_uint4 *) RelinquishMagickMemory(histogram);
4967
4968
4969 if (histogramKernel!=NULL)
4970 RelinquishOpenCLKernel(clEnv, histogramKernel);
4971 if (stretchKernel!=NULL)
4972 RelinquishOpenCLKernel(clEnv, stretchKernel);
4973
4974 if (queue != NULL)
4975 RelinquishOpenCLCommandQueue(clEnv, queue);
4976
4977 return outputReady;
4978}
4979
4980
4981/*
4982%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4983% %
4984% %
4985% %
4986% C o n t r a s t S t r e t c h I m a g e w i t h O p e n C L %
4987% %
4988% %
4989% %
4990%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4991%
4992% ContrastStretchImage() is a simple image enhancement technique that attempts
4993% to improve the contrast in an image by `stretching' the range of intensity
4994% values it contains to span a desired range of values. It differs from the
4995% more sophisticated histogram equalization in that it can only apply a
4996% linear scaling function to the image pixel values. As a result the
4997% `enhancement' is less harsh.
4998%
4999% The format of the ContrastStretchImage method is:
5000%
5001% MagickBooleanType ContrastStretchImage(Image *image,
5002% const char *levels)
5003% MagickBooleanType ContrastStretchImageChannel(Image *image,
5004% const size_t channel,const double black_point,
5005% const double white_point)
5006%
5007% A description of each parameter follows:
5008%
5009% o image: the image.
5010%
5011% o channel: the channel.
5012%
5013% o black_point: the black point.
5014%
5015% o white_point: the white point.
5016%
5017% o levels: Specify the levels where the black and white points have the
5018% range of 0 to number-of-pixels (e.g. 1%, 10x90%, etc.).
5019%
5020*/
5021
5022MagickExport MagickBooleanType AccelerateContrastStretchImageChannel(
5023 Image * image, const ChannelType channel, const double black_point, const double white_point,
5024 ExceptionInfo* exception)
5025{
5026 MagickBooleanType status;
5027
5028 assert(image != NULL);
5029 assert(exception != NULL);
5030
5031 status = checkOpenCLEnvironment(exception);
5032 if (status == MagickFalse)
5033 return MagickFalse;
5034
5035 status = checkAccelerateCondition(image, channel);
5036 if (status == MagickFalse)
5037 return MagickFalse;
5038
5039 status = checkHistogramCondition(image, channel);
5040 if (status == MagickFalse)
5041 return MagickFalse;
5042
5043 status = ComputeContrastStretchImageChannel(image,channel, black_point, white_point, exception);
5044
5045 return status;
5046}
5047
5048
cristyf034abb2013-11-24 14:16:14 +00005049static Image* ComputeDespeckleImage(const Image* inputImage, ExceptionInfo* exception)
5050{
5051
5052 MagickBooleanType outputReady = MagickFalse;
5053 MagickCLEnv clEnv = NULL;
5054
5055 cl_int clStatus;
5056 size_t global_work_size[2];
5057
5058 const void *inputPixels = NULL;
5059 Image* filteredImage = NULL;
5060 void *filteredPixels = NULL;
5061 void *hostPtr;
5062 MagickSizeType length;
5063
5064 cl_mem_flags mem_flags;
5065 cl_context context = NULL;
5066 cl_mem inputImageBuffer = NULL;
5067 cl_mem tempImageBuffer[2];
5068 cl_mem filteredImageBuffer = NULL;
5069 cl_command_queue queue = NULL;
5070 cl_kernel hullPass1 = NULL;
5071 cl_kernel hullPass2 = NULL;
5072
5073 unsigned int imageWidth, imageHeight;
5074 int matte;
5075 int k;
5076
5077 static const int
5078 X[4] = {0, 1, 1,-1},
5079 Y[4] = {1, 0, 1, 1};
5080
5081 tempImageBuffer[0] = tempImageBuffer[1] = NULL;
5082 clEnv = GetDefaultOpenCLEnv();
5083 context = GetOpenCLContext(clEnv);
5084 queue = AcquireOpenCLCommandQueue(clEnv);
5085
5086 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
5087 if (inputPixels == (void *) NULL)
5088 {
cristya22457d2013-12-07 14:03:06 +00005089 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
cristyf034abb2013-11-24 14:16:14 +00005090 goto cleanup;
5091 }
5092
5093 if (ALIGNED(inputPixels,CLPixelPacket))
5094 {
5095 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
5096 }
5097 else
5098 {
5099 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
5100 }
5101 /* create a CL buffer from image pixel buffer */
5102 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005103 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00005104 if (clStatus != CL_SUCCESS)
5105 {
cristy0c832c62014-03-07 22:21:04 +00005106 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00005107 goto cleanup;
5108 }
5109
5110 mem_flags = CL_MEM_READ_WRITE;
5111 length = inputImage->columns * inputImage->rows;
5112 for (k = 0; k < 2; k++)
5113 {
cristy0c832c62014-03-07 22:21:04 +00005114 tempImageBuffer[k] = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00005115 if (clStatus != CL_SUCCESS)
5116 {
cristy0c832c62014-03-07 22:21:04 +00005117 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00005118 goto cleanup;
5119 }
5120 }
5121
5122 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
5123 assert(filteredImage != NULL);
cristy0c832c62014-03-07 22:21:04 +00005124 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +00005125 {
cristya22457d2013-12-07 14:03:06 +00005126 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005127 goto cleanup;
5128 }
5129 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
5130 if (filteredPixels == (void *) NULL)
5131 {
cristya22457d2013-12-07 14:03:06 +00005132 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +00005133 goto cleanup;
5134 }
5135
5136 if (ALIGNED(filteredPixels,CLPixelPacket))
5137 {
5138 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
5139 hostPtr = filteredPixels;
5140 }
5141 else
5142 {
5143 mem_flags = CL_MEM_WRITE_ONLY;
5144 hostPtr = NULL;
5145 }
5146 /* create a CL buffer from image pixel buffer */
5147 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005148 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00005149 if (clStatus != CL_SUCCESS)
5150 {
cristy0c832c62014-03-07 22:21:04 +00005151 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00005152 goto cleanup;
5153 }
5154
5155 hullPass1 = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "HullPass1");
5156 hullPass2 = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "HullPass2");
5157
cristy0c832c62014-03-07 22:21:04 +00005158 clStatus =clEnv->library->clSetKernelArg(hullPass1,0,sizeof(cl_mem),(void *)&inputImageBuffer);
5159 clStatus |=clEnv->library->clSetKernelArg(hullPass1,1,sizeof(cl_mem),(void *)(tempImageBuffer+1));
cristyf034abb2013-11-24 14:16:14 +00005160 imageWidth = inputImage->columns;
cristy0c832c62014-03-07 22:21:04 +00005161 clStatus |=clEnv->library->clSetKernelArg(hullPass1,2,sizeof(unsigned int),(void *)&imageWidth);
cristyf034abb2013-11-24 14:16:14 +00005162 imageHeight = inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005163 clStatus |=clEnv->library->clSetKernelArg(hullPass1,3,sizeof(unsigned int),(void *)&imageHeight);
cristya22457d2013-12-07 14:03:06 +00005164 matte = (inputImage->matte==MagickFalse)?0:1;
cristy0c832c62014-03-07 22:21:04 +00005165 clStatus |=clEnv->library->clSetKernelArg(hullPass1,6,sizeof(int),(void *)&matte);
cristyf034abb2013-11-24 14:16:14 +00005166 if (clStatus != CL_SUCCESS)
5167 {
cristy0c832c62014-03-07 22:21:04 +00005168 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005169 goto cleanup;
5170 }
5171
cristy0c832c62014-03-07 22:21:04 +00005172 clStatus = clEnv->library->clSetKernelArg(hullPass2,0,sizeof(cl_mem),(void *)(tempImageBuffer+1));
5173 clStatus |=clEnv->library->clSetKernelArg(hullPass2,1,sizeof(cl_mem),(void *)tempImageBuffer);
cristyf034abb2013-11-24 14:16:14 +00005174 imageWidth = inputImage->columns;
cristy0c832c62014-03-07 22:21:04 +00005175 clStatus |=clEnv->library->clSetKernelArg(hullPass2,2,sizeof(unsigned int),(void *)&imageWidth);
cristyf034abb2013-11-24 14:16:14 +00005176 imageHeight = inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005177 clStatus |=clEnv->library->clSetKernelArg(hullPass2,3,sizeof(unsigned int),(void *)&imageHeight);
5178 matte = (inputImage->matte==MagickFalse)?0:1;
5179 clStatus |=clEnv->library->clSetKernelArg(hullPass2,6,sizeof(int),(void *)&matte);
cristyf034abb2013-11-24 14:16:14 +00005180 if (clStatus != CL_SUCCESS)
5181 {
cristy0c832c62014-03-07 22:21:04 +00005182 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005183 goto cleanup;
5184 }
5185
5186
5187 global_work_size[0] = inputImage->columns;
5188 global_work_size[1] = inputImage->rows;
5189
5190
5191 for (k = 0; k < 4; k++)
5192 {
5193 cl_int2 offset;
5194 int polarity;
5195
5196
5197 offset.s[0] = X[k];
5198 offset.s[1] = Y[k];
5199 polarity = 1;
cristy0c832c62014-03-07 22:21:04 +00005200 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
5201 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
5202 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
5203 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
cristyf034abb2013-11-24 14:16:14 +00005204 if (clStatus != CL_SUCCESS)
5205 {
cristy0c832c62014-03-07 22:21:04 +00005206 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005207 goto cleanup;
5208 }
5209 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005210 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005211 if (clStatus != CL_SUCCESS)
5212 {
cristy0c832c62014-03-07 22:21:04 +00005213 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005214 goto cleanup;
5215 }
5216 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005217 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005218 if (clStatus != CL_SUCCESS)
5219 {
cristy0c832c62014-03-07 22:21:04 +00005220 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005221 goto cleanup;
5222 }
5223
5224
5225 if (k == 0)
cristy0c832c62014-03-07 22:21:04 +00005226 clStatus =clEnv->library->clSetKernelArg(hullPass1,0,sizeof(cl_mem),(void *)(tempImageBuffer));
cristyf034abb2013-11-24 14:16:14 +00005227 offset.s[0] = -X[k];
5228 offset.s[1] = -Y[k];
5229 polarity = 1;
cristy0c832c62014-03-07 22:21:04 +00005230 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
5231 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
5232 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
5233 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
cristyf034abb2013-11-24 14:16:14 +00005234 if (clStatus != CL_SUCCESS)
5235 {
cristy0c832c62014-03-07 22:21:04 +00005236 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005237 goto cleanup;
5238 }
5239 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005240 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005241 if (clStatus != CL_SUCCESS)
5242 {
cristy0c832c62014-03-07 22:21:04 +00005243 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005244 goto cleanup;
5245 }
5246 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005247 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005248 if (clStatus != CL_SUCCESS)
5249 {
cristy0c832c62014-03-07 22:21:04 +00005250 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005251 goto cleanup;
5252 }
5253
5254 offset.s[0] = -X[k];
5255 offset.s[1] = -Y[k];
5256 polarity = -1;
cristy0c832c62014-03-07 22:21:04 +00005257 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
5258 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
5259 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
5260 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
cristyf034abb2013-11-24 14:16:14 +00005261 if (clStatus != CL_SUCCESS)
5262 {
cristy0c832c62014-03-07 22:21:04 +00005263 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005264 goto cleanup;
5265 }
5266 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005267 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005268 if (clStatus != CL_SUCCESS)
5269 {
cristy0c832c62014-03-07 22:21:04 +00005270 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005271 goto cleanup;
5272 }
5273 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005274 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005275 if (clStatus != CL_SUCCESS)
5276 {
cristy0c832c62014-03-07 22:21:04 +00005277 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005278 goto cleanup;
5279 }
5280
5281 offset.s[0] = X[k];
5282 offset.s[1] = Y[k];
5283 polarity = -1;
cristy0c832c62014-03-07 22:21:04 +00005284 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
5285 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
5286 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
5287 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
cristyf034abb2013-11-24 14:16:14 +00005288
5289 if (k == 3)
cristy0c832c62014-03-07 22:21:04 +00005290 clStatus |=clEnv->library->clSetKernelArg(hullPass2,1,sizeof(cl_mem),(void *)&filteredImageBuffer);
cristyf034abb2013-11-24 14:16:14 +00005291
5292 if (clStatus != CL_SUCCESS)
5293 {
cristy0c832c62014-03-07 22:21:04 +00005294 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005295 goto cleanup;
5296 }
5297 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005298 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005299 if (clStatus != CL_SUCCESS)
5300 {
cristy0c832c62014-03-07 22:21:04 +00005301 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005302 goto cleanup;
5303 }
5304 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005305 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005306 if (clStatus != CL_SUCCESS)
5307 {
cristy0c832c62014-03-07 22:21:04 +00005308 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005309 goto cleanup;
5310 }
5311 }
5312
5313 if (ALIGNED(filteredPixels,CLPixelPacket))
5314 {
5315 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005316 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 +00005317 }
5318 else
5319 {
5320 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005321 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005322 }
5323 if (clStatus != CL_SUCCESS)
5324 {
cristya22457d2013-12-07 14:03:06 +00005325 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005326 goto cleanup;
5327 }
5328
5329 outputReady = MagickTrue;
5330
5331cleanup:
cristya22457d2013-12-07 14:03:06 +00005332 OpenCLLogException(__FUNCTION__,__LINE__,exception);
5333
cristyf034abb2013-11-24 14:16:14 +00005334 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
cristy0c832c62014-03-07 22:21:04 +00005335 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer);
cristyf034abb2013-11-24 14:16:14 +00005336 for (k = 0; k < 2; k++)
5337 {
cristy0c832c62014-03-07 22:21:04 +00005338 if (tempImageBuffer[k]!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer[k]);
cristyf034abb2013-11-24 14:16:14 +00005339 }
cristy0c832c62014-03-07 22:21:04 +00005340 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
cristyf034abb2013-11-24 14:16:14 +00005341 if (hullPass1!=NULL) RelinquishOpenCLKernel(clEnv, hullPass1);
5342 if (hullPass2!=NULL) RelinquishOpenCLKernel(clEnv, hullPass2);
5343 if (outputReady == MagickFalse)
5344 {
5345 if (filteredImage != NULL)
5346 {
5347 DestroyImage(filteredImage);
5348 filteredImage = NULL;
5349 }
5350 }
5351 return filteredImage;
5352}
5353
5354/*
5355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5356% %
5357% %
5358% %
5359% D e s p e c k l e I m a g e w i t h O p e n C L %
5360% %
5361% %
5362% %
5363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5364%
5365% DespeckleImage() reduces the speckle noise in an image while perserving the
5366% edges of the original image. A speckle removing filter uses a complementary
5367% hulling technique (raising pixels that are darker than their surrounding
5368% neighbors, then complementarily lowering pixels that are brighter than their
5369% surrounding neighbors) to reduce the speckle index of that image (reference
5370% Crimmins speckle removal).
5371%
5372% The format of the DespeckleImage method is:
5373%
5374% Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
5375%
5376% A description of each parameter follows:
5377%
5378% o image: the image.
5379%
5380% o exception: return any errors or warnings in this structure.
5381%
5382*/
5383
5384MagickExport
5385Image* AccelerateDespeckleImage(const Image* image, ExceptionInfo* exception)
5386{
5387 MagickBooleanType status;
5388 Image* newImage = NULL;
5389
5390 assert(image != NULL);
5391 assert(exception != NULL);
5392
5393 status = checkOpenCLEnvironment(exception);
5394 if (status == MagickFalse)
5395 return NULL;
5396
dirk5dcb7622013-12-01 10:43:43 +00005397 status = checkAccelerateCondition(image, AllChannels);
cristyf034abb2013-11-24 14:16:14 +00005398 if (status == MagickFalse)
5399 return NULL;
5400
5401 newImage = ComputeDespeckleImage(image,exception);
cristyf034abb2013-11-24 14:16:14 +00005402 return newImage;
5403}
5404
cristye85d0f72013-11-27 02:25:43 +00005405static Image* ComputeAddNoiseImage(const Image* inputImage,
5406 const ChannelType channel, const NoiseType noise_type,
5407 ExceptionInfo *exception)
5408{
5409 MagickBooleanType outputReady = MagickFalse;
5410 MagickCLEnv clEnv = NULL;
5411
5412 cl_int clStatus;
5413 size_t global_work_size[2];
5414
5415 const void *inputPixels = NULL;
5416 Image* filteredImage = NULL;
5417 void *filteredPixels = NULL;
5418 void *hostPtr;
5419 unsigned int inputColumns, inputRows;
5420 float attenuate;
5421 float *randomNumberBufferPtr = NULL;
5422 MagickSizeType length;
5423 unsigned int numRandomNumberPerPixel;
5424 unsigned int numRowsPerKernelLaunch;
5425 unsigned int numRandomNumberPerBuffer;
5426 unsigned int r;
5427 unsigned int k;
5428 int i;
5429
5430 RandomInfo **restrict random_info;
5431 const char *option;
5432#if defined(MAGICKCORE_OPENMP_SUPPORT)
5433 unsigned long key;
5434#endif
5435
5436 cl_mem_flags mem_flags;
5437 cl_context context = NULL;
5438 cl_mem inputImageBuffer = NULL;
5439 cl_mem randomNumberBuffer = NULL;
5440 cl_mem filteredImageBuffer = NULL;
5441 cl_command_queue queue = NULL;
5442 cl_kernel addNoiseKernel = NULL;
5443
5444
5445 clEnv = GetDefaultOpenCLEnv();
5446 context = GetOpenCLContext(clEnv);
5447 queue = AcquireOpenCLCommandQueue(clEnv);
5448
5449 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
5450 if (inputPixels == (void *) NULL)
5451 {
cristya22457d2013-12-07 14:03:06 +00005452 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
cristye85d0f72013-11-27 02:25:43 +00005453 goto cleanup;
5454 }
5455
5456 if (ALIGNED(inputPixels,CLPixelPacket))
5457 {
5458 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
5459 }
5460 else
5461 {
5462 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
5463 }
5464 /* create a CL buffer from image pixel buffer */
5465 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005466 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristye85d0f72013-11-27 02:25:43 +00005467 if (clStatus != CL_SUCCESS)
5468 {
cristy0c832c62014-03-07 22:21:04 +00005469 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristye85d0f72013-11-27 02:25:43 +00005470 goto cleanup;
5471 }
5472
5473
5474 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
5475 assert(filteredImage != NULL);
cristy0c832c62014-03-07 22:21:04 +00005476 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
cristye85d0f72013-11-27 02:25:43 +00005477 {
cristya22457d2013-12-07 14:03:06 +00005478 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristye85d0f72013-11-27 02:25:43 +00005479 goto cleanup;
5480 }
5481 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
5482 if (filteredPixels == (void *) NULL)
5483 {
cristya22457d2013-12-07 14:03:06 +00005484 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristye85d0f72013-11-27 02:25:43 +00005485 goto cleanup;
5486 }
5487
5488 if (ALIGNED(filteredPixels,CLPixelPacket))
5489 {
5490 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
5491 hostPtr = filteredPixels;
5492 }
5493 else
5494 {
5495 mem_flags = CL_MEM_WRITE_ONLY;
5496 hostPtr = NULL;
5497 }
5498 /* create a CL buffer from image pixel buffer */
5499 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005500 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristye85d0f72013-11-27 02:25:43 +00005501 if (clStatus != CL_SUCCESS)
5502 {
cristy0c832c62014-03-07 22:21:04 +00005503 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristye85d0f72013-11-27 02:25:43 +00005504 goto cleanup;
5505 }
5506
5507 /* find out how many random numbers needed by pixel */
5508 numRandomNumberPerPixel = 0;
5509 {
5510 unsigned int numRandPerChannel = 0;
5511 switch (noise_type)
5512 {
5513 case UniformNoise:
5514 case ImpulseNoise:
5515 case LaplacianNoise:
5516 case RandomNoise:
5517 default:
5518 numRandPerChannel = 1;
5519 break;
5520 case GaussianNoise:
5521 case MultiplicativeGaussianNoise:
5522 case PoissonNoise:
5523 numRandPerChannel = 2;
5524 break;
5525 };
5526
5527 if ((channel & RedChannel) != 0)
5528 numRandomNumberPerPixel+=numRandPerChannel;
5529 if ((channel & GreenChannel) != 0)
5530 numRandomNumberPerPixel+=numRandPerChannel;
5531 if ((channel & BlueChannel) != 0)
5532 numRandomNumberPerPixel+=numRandPerChannel;
5533 if ((channel & OpacityChannel) != 0)
5534 numRandomNumberPerPixel+=numRandPerChannel;
5535 }
5536
5537 numRowsPerKernelLaunch = 512;
5538 /* create a buffer for random numbers */
5539 numRandomNumberPerBuffer = (inputImage->columns*numRowsPerKernelLaunch)*numRandomNumberPerPixel;
cristy0c832c62014-03-07 22:21:04 +00005540 randomNumberBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, numRandomNumberPerBuffer*sizeof(float)
cristye85d0f72013-11-27 02:25:43 +00005541 , NULL, &clStatus);
5542
5543
5544 /* set up the random number generators */
5545 attenuate=1.0;
5546 option=GetImageArtifact(inputImage,"attenuate");
5547 if (option != (char *) NULL)
5548 attenuate=StringToDouble(option,(char **) NULL);
5549 random_info=AcquireRandomInfoThreadSet();
5550#if defined(MAGICKCORE_OPENMP_SUPPORT)
5551 key=GetRandomSecretKey(random_info[0]);
5552#endif
5553
5554 addNoiseKernel = AcquireOpenCLKernel(clEnv,MAGICK_OPENCL_ACCELERATE,"AddNoiseImage");
5555
5556 k = 0;
cristy0c832c62014-03-07 22:21:04 +00005557 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&inputImageBuffer);
5558 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&filteredImageBuffer);
cristye85d0f72013-11-27 02:25:43 +00005559 inputColumns = inputImage->columns;
cristy0c832c62014-03-07 22:21:04 +00005560 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputColumns);
cristye85d0f72013-11-27 02:25:43 +00005561 inputRows = inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005562 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputRows);
5563 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(ChannelType),(void *)&channel);
5564 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(NoiseType),(void *)&noise_type);
cristye85d0f72013-11-27 02:25:43 +00005565 attenuate=1.0f;
5566 option=GetImageArtifact(inputImage,"attenuate");
5567 if (option != (char *) NULL)
5568 attenuate=(float)StringToDouble(option,(char **) NULL);
cristy0c832c62014-03-07 22:21:04 +00005569 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(float),(void *)&attenuate);
5570 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&randomNumberBuffer);
5571 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&numRandomNumberPerPixel);
cristye85d0f72013-11-27 02:25:43 +00005572
5573 global_work_size[0] = inputColumns;
5574 for (r = 0; r < inputRows; r+=numRowsPerKernelLaunch)
5575 {
5576 /* Generate random numbers in the buffer */
cristy0c832c62014-03-07 22:21:04 +00005577 randomNumberBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, randomNumberBuffer, CL_TRUE, CL_MAP_WRITE, 0
cristye85d0f72013-11-27 02:25:43 +00005578 , numRandomNumberPerBuffer*sizeof(float), 0, NULL, NULL, &clStatus);
5579 if (clStatus != CL_SUCCESS)
5580 {
cristy0c832c62014-03-07 22:21:04 +00005581 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristye85d0f72013-11-27 02:25:43 +00005582 goto cleanup;
5583 }
5584
5585#if defined(MAGICKCORE_OPENMP_SUPPORT)
5586 #pragma omp parallel for schedule(static,4) \
5587 num_threads((key == ~0UL) == 0 ? 1 : (size_t) GetMagickResourceLimit(ThreadResource))
5588#endif
5589 for (i = 0; i < numRandomNumberPerBuffer; i++)
5590 {
5591 const int id = GetOpenMPThreadId();
5592 randomNumberBufferPtr[i] = (float)GetPseudoRandomValue(random_info[id]);
5593 }
5594
cristy0c832c62014-03-07 22:21:04 +00005595 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, randomNumberBuffer, randomNumberBufferPtr, 0, NULL, NULL);
cristye85d0f72013-11-27 02:25:43 +00005596 if (clStatus != CL_SUCCESS)
5597 {
cristy0c832c62014-03-07 22:21:04 +00005598 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.",".");
cristye85d0f72013-11-27 02:25:43 +00005599 goto cleanup;
5600 }
5601
5602 /* set the row offset */
cristy0c832c62014-03-07 22:21:04 +00005603 clEnv->library->clSetKernelArg(addNoiseKernel,k,sizeof(unsigned int),(void *)&r);
cristye85d0f72013-11-27 02:25:43 +00005604 global_work_size[1] = MAGICK_MIN(numRowsPerKernelLaunch, inputRows - r);
cristy0c832c62014-03-07 22:21:04 +00005605 clEnv->library->clEnqueueNDRangeKernel(queue,addNoiseKernel,2,NULL,global_work_size,NULL,0,NULL,NULL);
cristye85d0f72013-11-27 02:25:43 +00005606 }
5607
5608 if (ALIGNED(filteredPixels,CLPixelPacket))
5609 {
5610 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005611 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 +00005612 }
5613 else
5614 {
5615 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005616 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristye85d0f72013-11-27 02:25:43 +00005617 }
5618 if (clStatus != CL_SUCCESS)
5619 {
cristya22457d2013-12-07 14:03:06 +00005620 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristye85d0f72013-11-27 02:25:43 +00005621 goto cleanup;
5622 }
5623
cristye85d0f72013-11-27 02:25:43 +00005624 outputReady = MagickTrue;
cristya22457d2013-12-07 14:03:06 +00005625
cristye85d0f72013-11-27 02:25:43 +00005626cleanup:
cristya22457d2013-12-07 14:03:06 +00005627 OpenCLLogException(__FUNCTION__,__LINE__,exception);
5628
cristye85d0f72013-11-27 02:25:43 +00005629 if (queue!=NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
5630 if (addNoiseKernel!=NULL) RelinquishOpenCLKernel(clEnv, addNoiseKernel);
cristy0c832c62014-03-07 22:21:04 +00005631 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer);
5632 if (randomNumberBuffer!=NULL) clEnv->library->clReleaseMemObject(randomNumberBuffer);
5633 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
cristye85d0f72013-11-27 02:25:43 +00005634 if (outputReady == MagickFalse
5635 && filteredImage != NULL)
5636 {
5637 DestroyImage(filteredImage);
5638 filteredImage = NULL;
5639 }
5640 return filteredImage;
5641}
5642
5643
5644static Image* ComputeAddNoiseImageOptRandomNum(const Image* inputImage,
5645 const ChannelType channel, const NoiseType noise_type,
5646 ExceptionInfo *exception)
5647{
5648 MagickBooleanType outputReady = MagickFalse;
5649 MagickCLEnv clEnv = NULL;
5650
5651 cl_int clStatus;
5652 size_t global_work_size[2];
5653 size_t random_work_size;
5654
5655 const void *inputPixels = NULL;
5656 Image* filteredImage = NULL;
5657 void *filteredPixels = NULL;
5658 void *hostPtr;
5659 unsigned int inputColumns, inputRows;
5660 float attenuate;
5661 MagickSizeType length;
5662 unsigned int numRandomNumberPerPixel;
5663 unsigned int numRowsPerKernelLaunch;
5664 unsigned int numRandomNumberPerBuffer;
5665 unsigned int numRandomNumberGenerators;
5666 unsigned int initRandom;
5667 float fNormalize;
5668 unsigned int r;
5669 unsigned int k;
5670 int i;
5671 const char *option;
5672
5673 cl_mem_flags mem_flags;
5674 cl_context context = NULL;
5675 cl_mem inputImageBuffer = NULL;
5676 cl_mem randomNumberBuffer = NULL;
5677 cl_mem filteredImageBuffer = NULL;
5678 cl_mem randomNumberSeedsBuffer = NULL;
5679 cl_command_queue queue = NULL;
5680 cl_kernel addNoiseKernel = NULL;
5681 cl_kernel randomNumberGeneratorKernel = NULL;
5682
5683
5684 clEnv = GetDefaultOpenCLEnv();
5685 context = GetOpenCLContext(clEnv);
5686 queue = AcquireOpenCLCommandQueue(clEnv);
5687
5688 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
5689 if (inputPixels == (void *) NULL)
5690 {
cristya22457d2013-12-07 14:03:06 +00005691 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
cristye85d0f72013-11-27 02:25:43 +00005692 goto cleanup;
5693 }
5694
5695 if (ALIGNED(inputPixels,CLPixelPacket))
5696 {
5697 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
5698 }
5699 else
5700 {
5701 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
5702 }
5703 /* create a CL buffer from image pixel buffer */
5704 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005705 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristye85d0f72013-11-27 02:25:43 +00005706 if (clStatus != CL_SUCCESS)
5707 {
cristy0c832c62014-03-07 22:21:04 +00005708 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristye85d0f72013-11-27 02:25:43 +00005709 goto cleanup;
5710 }
5711
5712
5713 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
5714 assert(filteredImage != NULL);
cristy0c832c62014-03-07 22:21:04 +00005715 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
cristye85d0f72013-11-27 02:25:43 +00005716 {
cristya22457d2013-12-07 14:03:06 +00005717 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristye85d0f72013-11-27 02:25:43 +00005718 goto cleanup;
5719 }
5720 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
5721 if (filteredPixels == (void *) NULL)
5722 {
cristya22457d2013-12-07 14:03:06 +00005723 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristye85d0f72013-11-27 02:25:43 +00005724 goto cleanup;
5725 }
5726
5727 if (ALIGNED(filteredPixels,CLPixelPacket))
5728 {
5729 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
5730 hostPtr = filteredPixels;
5731 }
5732 else
5733 {
5734 mem_flags = CL_MEM_WRITE_ONLY;
5735 hostPtr = NULL;
5736 }
5737 /* create a CL buffer from image pixel buffer */
5738 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005739 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristye85d0f72013-11-27 02:25:43 +00005740 if (clStatus != CL_SUCCESS)
5741 {
cristy0c832c62014-03-07 22:21:04 +00005742 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristye85d0f72013-11-27 02:25:43 +00005743 goto cleanup;
5744 }
5745
5746 /* find out how many random numbers needed by pixel */
5747 numRandomNumberPerPixel = 0;
5748 {
5749 unsigned int numRandPerChannel = 0;
5750 switch (noise_type)
5751 {
5752 case UniformNoise:
5753 case ImpulseNoise:
5754 case LaplacianNoise:
5755 case RandomNoise:
5756 default:
5757 numRandPerChannel = 1;
5758 break;
5759 case GaussianNoise:
5760 case MultiplicativeGaussianNoise:
5761 case PoissonNoise:
5762 numRandPerChannel = 2;
5763 break;
5764 };
5765
5766 if ((channel & RedChannel) != 0)
5767 numRandomNumberPerPixel+=numRandPerChannel;
5768 if ((channel & GreenChannel) != 0)
5769 numRandomNumberPerPixel+=numRandPerChannel;
5770 if ((channel & BlueChannel) != 0)
5771 numRandomNumberPerPixel+=numRandPerChannel;
5772 if ((channel & OpacityChannel) != 0)
5773 numRandomNumberPerPixel+=numRandPerChannel;
5774 }
5775
5776 numRowsPerKernelLaunch = 512;
5777
5778 /* create a buffer for random numbers */
5779 numRandomNumberPerBuffer = (inputImage->columns*numRowsPerKernelLaunch)*numRandomNumberPerPixel;
cristy0c832c62014-03-07 22:21:04 +00005780 randomNumberBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, numRandomNumberPerBuffer*sizeof(float)
cristye85d0f72013-11-27 02:25:43 +00005781 , NULL, &clStatus);
5782
5783 {
5784 /* setup the random number generators */
5785 unsigned long* seeds;
5786 numRandomNumberGenerators = 512;
cristy0c832c62014-03-07 22:21:04 +00005787 randomNumberSeedsBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_ALLOC_HOST_PTR|CL_MEM_READ_WRITE
cristye85d0f72013-11-27 02:25:43 +00005788 , numRandomNumberGenerators * 4 * sizeof(unsigned long), NULL, &clStatus);
5789 if (clStatus != CL_SUCCESS)
5790 {
cristy0c832c62014-03-07 22:21:04 +00005791 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristye85d0f72013-11-27 02:25:43 +00005792 goto cleanup;
5793 }
cristy0c832c62014-03-07 22:21:04 +00005794 seeds = (unsigned long*) clEnv->library->clEnqueueMapBuffer(queue, randomNumberSeedsBuffer, CL_TRUE, CL_MAP_WRITE, 0
cristye85d0f72013-11-27 02:25:43 +00005795 , numRandomNumberGenerators*4*sizeof(unsigned long), 0, NULL, NULL, &clStatus);
5796 if (clStatus != CL_SUCCESS)
5797 {
cristy0c832c62014-03-07 22:21:04 +00005798 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristye85d0f72013-11-27 02:25:43 +00005799 goto cleanup;
5800 }
5801
5802 for (i = 0; i < numRandomNumberGenerators; i++) {
5803 RandomInfo* randomInfo = AcquireRandomInfo();
5804 const unsigned long* s = GetRandomInfoSeed(randomInfo);
5805
5806 if (i == 0)
5807 fNormalize = GetRandomInfoNormalize(randomInfo);
5808
5809 seeds[i*4] = s[0];
5810 randomInfo = DestroyRandomInfo(randomInfo);
5811 }
5812
cristy0c832c62014-03-07 22:21:04 +00005813 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, randomNumberSeedsBuffer, seeds, 0, NULL, NULL);
cristye85d0f72013-11-27 02:25:43 +00005814 if (clStatus != CL_SUCCESS)
5815 {
cristy0c832c62014-03-07 22:21:04 +00005816 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.",".");
cristye85d0f72013-11-27 02:25:43 +00005817 goto cleanup;
5818 }
5819
5820 randomNumberGeneratorKernel = AcquireOpenCLKernel(clEnv,MAGICK_OPENCL_ACCELERATE
5821 ,"randomNumberGeneratorKernel");
5822
5823 k = 0;
cristy0c832c62014-03-07 22:21:04 +00005824 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(cl_mem),(void *)&randomNumberSeedsBuffer);
5825 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(float),(void *)&fNormalize);
5826 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(cl_mem),(void *)&randomNumberBuffer);
cristye85d0f72013-11-27 02:25:43 +00005827 initRandom = 1;
cristy0c832c62014-03-07 22:21:04 +00005828 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(unsigned int),(void *)&initRandom);
5829 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(unsigned int),(void *)&numRandomNumberPerBuffer);
cristye85d0f72013-11-27 02:25:43 +00005830
5831 random_work_size = numRandomNumberGenerators;
5832 }
5833
5834 addNoiseKernel = AcquireOpenCLKernel(clEnv,MAGICK_OPENCL_ACCELERATE,"AddNoiseImage");
5835 k = 0;
cristy0c832c62014-03-07 22:21:04 +00005836 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&inputImageBuffer);
5837 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&filteredImageBuffer);
cristye85d0f72013-11-27 02:25:43 +00005838 inputColumns = inputImage->columns;
cristy0c832c62014-03-07 22:21:04 +00005839 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputColumns);
cristye85d0f72013-11-27 02:25:43 +00005840 inputRows = inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005841 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputRows);
5842 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(ChannelType),(void *)&channel);
5843 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(NoiseType),(void *)&noise_type);
cristye85d0f72013-11-27 02:25:43 +00005844 attenuate=1.0f;
5845 option=GetImageArtifact(inputImage,"attenuate");
5846 if (option != (char *) NULL)
5847 attenuate=(float)StringToDouble(option,(char **) NULL);
cristy0c832c62014-03-07 22:21:04 +00005848 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(float),(void *)&attenuate);
5849 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&randomNumberBuffer);
5850 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&numRandomNumberPerPixel);
cristye85d0f72013-11-27 02:25:43 +00005851
5852 global_work_size[0] = inputColumns;
5853 for (r = 0; r < inputRows; r+=numRowsPerKernelLaunch)
5854 {
5855 size_t generator_local_size = 64;
5856 /* Generate random numbers in the buffer */
cristy0c832c62014-03-07 22:21:04 +00005857 clEnv->library->clEnqueueNDRangeKernel(queue,randomNumberGeneratorKernel,1,NULL
cristye85d0f72013-11-27 02:25:43 +00005858 ,&random_work_size,&generator_local_size,0,NULL,NULL);
5859 if (initRandom != 0)
5860 {
5861 /* make sure we only do init once */
5862 initRandom = 0;
cristy0c832c62014-03-07 22:21:04 +00005863 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,3,sizeof(unsigned int),(void *)&initRandom);
cristye85d0f72013-11-27 02:25:43 +00005864 }
5865
5866 /* set the row offset */
cristy0c832c62014-03-07 22:21:04 +00005867 clEnv->library->clSetKernelArg(addNoiseKernel,k,sizeof(unsigned int),(void *)&r);
cristye85d0f72013-11-27 02:25:43 +00005868 global_work_size[1] = MAGICK_MIN(numRowsPerKernelLaunch, inputRows - r);
cristy0c832c62014-03-07 22:21:04 +00005869 clEnv->library->clEnqueueNDRangeKernel(queue,addNoiseKernel,2,NULL,global_work_size,NULL,0,NULL,NULL);
cristye85d0f72013-11-27 02:25:43 +00005870 }
5871
5872 if (ALIGNED(filteredPixels,CLPixelPacket))
5873 {
5874 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005875 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 +00005876 }
5877 else
5878 {
5879 length = inputImage->columns * inputImage->rows;
cristy0c832c62014-03-07 22:21:04 +00005880 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristye85d0f72013-11-27 02:25:43 +00005881 }
5882 if (clStatus != CL_SUCCESS)
5883 {
cristya22457d2013-12-07 14:03:06 +00005884 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristye85d0f72013-11-27 02:25:43 +00005885 goto cleanup;
5886 }
5887
cristye85d0f72013-11-27 02:25:43 +00005888 outputReady = MagickTrue;
cristya22457d2013-12-07 14:03:06 +00005889
cristye85d0f72013-11-27 02:25:43 +00005890cleanup:
cristya22457d2013-12-07 14:03:06 +00005891 OpenCLLogException(__FUNCTION__,__LINE__,exception);
5892
cristye85d0f72013-11-27 02:25:43 +00005893 if (queue!=NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
5894 if (addNoiseKernel!=NULL) RelinquishOpenCLKernel(clEnv, addNoiseKernel);
5895 if (randomNumberGeneratorKernel!=NULL) RelinquishOpenCLKernel(clEnv, randomNumberGeneratorKernel);
cristy0c832c62014-03-07 22:21:04 +00005896 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer);
5897 if (randomNumberBuffer!=NULL) clEnv->library->clReleaseMemObject(randomNumberBuffer);
5898 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
5899 if (randomNumberSeedsBuffer!=NULL) clEnv->library->clReleaseMemObject(randomNumberSeedsBuffer);
cristye85d0f72013-11-27 02:25:43 +00005900 if (outputReady == MagickFalse
5901 && filteredImage != NULL)
5902 {
5903 DestroyImage(filteredImage);
5904 filteredImage = NULL;
5905 }
5906 return filteredImage;
5907}
5908
5909
5910
5911MagickExport
5912Image* AccelerateAddNoiseImage(const Image *image, const ChannelType channel,
5913 const NoiseType noise_type,ExceptionInfo *exception)
5914{
5915 MagickBooleanType status;
5916 Image* filteredImage = NULL;
5917
5918 assert(image != NULL);
5919 assert(exception != NULL);
5920
5921 status = checkOpenCLEnvironment(exception);
5922 if (status == MagickFalse)
5923 return NULL;
5924
dirk5dcb7622013-12-01 10:43:43 +00005925 status = checkAccelerateCondition(image, channel);
cristye85d0f72013-11-27 02:25:43 +00005926 if (status == MagickFalse)
5927 return NULL;
5928
dirke3c5f892013-12-10 06:04:40 +00005929DisableMSCWarning(4127)
cristye85d0f72013-11-27 02:25:43 +00005930 if (sizeof(unsigned long) == 4)
dirke3c5f892013-12-10 06:04:40 +00005931RestoreMSCWarning
cristye85d0f72013-11-27 02:25:43 +00005932 filteredImage = ComputeAddNoiseImageOptRandomNum(image,channel,noise_type,exception);
5933 else
5934 filteredImage = ComputeAddNoiseImage(image,channel,noise_type,exception);
5935
cristye85d0f72013-11-27 02:25:43 +00005936 return filteredImage;
5937}
5938
cristy0c832c62014-03-07 22:21:04 +00005939static MagickBooleanType LaunchRandomImageKernel(MagickCLEnv clEnv,
5940 cl_command_queue queue,
5941 cl_mem inputImageBuffer,
5942 const unsigned int imageColumns,
5943 const unsigned int imageRows,
5944 cl_mem seedBuffer,
5945 const unsigned int numGenerators,
5946 ExceptionInfo *exception)
5947{
5948 MagickBooleanType status = MagickFalse;
5949 size_t global_work_size;
5950 size_t local_work_size;
5951 int k;
5952
5953 cl_int clStatus;
5954 cl_kernel randomImageKernel = NULL;
5955
5956 randomImageKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "RandomImage");
5957
5958 k = 0;
5959 clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_mem),(void*)&inputImageBuffer);
5960 clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_uint),(void*)&imageColumns);
5961 clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_uint),(void*)&imageRows);
5962 clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_mem),(void*)&seedBuffer);
5963 {
5964 const float randNormNumerator = 1.0f;
5965 const unsigned int randNormDenominator = (unsigned int)(~0UL);
5966 clEnv->library->clSetKernelArg(randomImageKernel,k++,
5967 sizeof(float),(void*)&randNormNumerator);
5968 clEnv->library->clSetKernelArg(randomImageKernel,k++,
5969 sizeof(cl_uint),(void*)&randNormDenominator);
5970 }
5971
5972
5973 global_work_size = numGenerators;
5974 local_work_size = 64;
5975
5976 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue,randomImageKernel,1,NULL,&global_work_size,
5977 &local_work_size,0,NULL,NULL);
5978
5979 if (clStatus != CL_SUCCESS)
5980 {
5981 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning,
5982 "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
5983 goto cleanup;
5984 }
5985 status = MagickTrue;
5986
5987cleanup:
5988 if (randomImageKernel!=NULL) RelinquishOpenCLKernel(clEnv, randomImageKernel);
5989 return status;
5990}
5991
5992static MagickBooleanType ComputeRandomImage(Image* inputImage,
5993 ExceptionInfo* exception)
5994{
5995 MagickBooleanType status = MagickFalse;
5996
5997 MagickBooleanType outputReady = MagickFalse;
5998 MagickCLEnv clEnv = NULL;
5999
6000 cl_int clStatus;
6001
6002 void *inputPixels = NULL;
6003 MagickSizeType length;
6004
6005 cl_mem_flags mem_flags;
6006 cl_context context = NULL;
6007 cl_mem inputImageBuffer = NULL;
6008 cl_command_queue queue = NULL;
6009
6010 /* Don't release this buffer in this function !!! */
6011 cl_mem randomNumberSeedsBuffer;
6012
6013 clEnv = GetDefaultOpenCLEnv();
6014 context = GetOpenCLContext(clEnv);
6015
6016 /* Create and initialize OpenCL buffers. */
6017 inputPixels = GetPixelCachePixels(inputImage, &length, exception);
6018 if (inputPixels == (void *) NULL)
6019 {
6020 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
6021 goto cleanup;
6022 }
6023
6024 /* If the host pointer is aligned to the size of CLPixelPacket,
6025 then use the host buffer directly from the GPU; otherwise,
6026 create a buffer on the GPU and copy the data over */
6027 if (ALIGNED(inputPixels,CLPixelPacket))
6028 {
6029 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
6030 }
6031 else
6032 {
6033 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
6034 }
6035 /* create a CL buffer from image pixel buffer */
6036 length = inputImage->columns * inputImage->rows;
6037 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
6038 if (clStatus != CL_SUCCESS)
6039 {
6040 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
6041 goto cleanup;
6042 }
6043
6044 queue = AcquireOpenCLCommandQueue(clEnv);
6045
6046 randomNumberSeedsBuffer = GetAndLockRandSeedBuffer(clEnv);
6047 if (randomNumberSeedsBuffer==NULL)
6048 {
6049 (void) OpenCLThrowMagickException(exception, GetMagickModule(),
6050 ResourceLimitWarning, "Failed to get GPU random number generators.",
6051 "'%s'", ".");
6052 goto cleanup;
6053 }
6054
6055 status = LaunchRandomImageKernel(clEnv,queue,
6056 inputImageBuffer,
6057 inputImage->columns,
6058 inputImage->rows,
6059 randomNumberSeedsBuffer,
6060 GetNumRandGenerators(clEnv),
6061 exception);
6062 if (status==MagickFalse)
6063 {
6064 goto cleanup;
6065 }
6066
6067 if (ALIGNED(inputPixels,CLPixelPacket))
6068 {
6069 length = inputImage->columns * inputImage->rows;
6070 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
6071 }
6072 else
6073 {
6074 length = inputImage->columns * inputImage->rows;
6075 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
6076 }
6077 if (clStatus != CL_SUCCESS)
6078 {
6079 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
6080 goto cleanup;
6081 }
6082 outputReady = MagickTrue;
6083
6084cleanup:
6085 OpenCLLogException(__FUNCTION__,__LINE__,exception);
6086
6087 UnlockRandSeedBuffer(clEnv);
6088 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer);
6089 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
6090 return outputReady;
6091}
6092
6093MagickExport MagickBooleanType AccelerateRandomImage(Image* image, ExceptionInfo* exception)
6094{
6095 MagickBooleanType status = MagickFalse;
6096
6097 status = checkOpenCLEnvironment(exception);
6098 if (status==MagickFalse)
6099 return status;
6100
6101 status = checkAccelerateCondition(image, AllChannels);
6102 if (status==MagickFalse)
6103 return status;
6104
6105 status = ComputeRandomImage(image,exception);
6106 return status;
6107}
6108
6109static Image* ComputeMotionBlurImage(const Image *inputImage,
6110 const ChannelType channel, const double *kernel, const size_t width,
6111 const OffsetInfo *offset, ExceptionInfo *exception)
6112{
6113 MagickBooleanType outputReady;
6114 Image* filteredImage;
6115 MagickCLEnv clEnv;
6116
6117 cl_int clStatus;
6118 size_t global_work_size[2];
6119 size_t local_work_size[2];
6120
6121 cl_context context;
6122 cl_mem_flags mem_flags;
6123 cl_mem inputImageBuffer, filteredImageBuffer, imageKernelBuffer,
6124 offsetBuffer;
6125 cl_kernel motionBlurKernel;
6126 cl_command_queue queue;
6127
6128 const void *inputPixels;
6129 void *filteredPixels;
6130 void* hostPtr;
6131 float* kernelBufferPtr;
6132 int* offsetBufferPtr;
6133 MagickSizeType length;
6134 unsigned int matte;
6135 MagickPixelPacket bias;
6136 cl_float4 biasPixel;
6137 unsigned int imageWidth, imageHeight;
6138
6139 unsigned int i;
6140
6141 outputReady = MagickFalse;
6142 context = NULL;
6143 filteredImage = NULL;
6144 inputImageBuffer = NULL;
6145 filteredImageBuffer = NULL;
6146 imageKernelBuffer = NULL;
6147 motionBlurKernel = NULL;
6148 queue = NULL;
6149
6150
6151 clEnv = GetDefaultOpenCLEnv();
6152 context = GetOpenCLContext(clEnv);
6153
6154 /* Create and initialize OpenCL buffers. */
6155
6156 inputPixels = NULL;
6157 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
6158 if (inputPixels == (const void *) NULL)
6159 {
6160 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
6161 "UnableToReadPixelCache.","`%s'",inputImage->filename);
6162 goto cleanup;
6163 }
6164
6165 // If the host pointer is aligned to the size of CLPixelPacket,
6166 // then use the host buffer directly from the GPU; otherwise,
6167 // create a buffer on the GPU and copy the data over
6168 if (ALIGNED(inputPixels,CLPixelPacket))
6169 {
6170 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
6171 }
6172 else
6173 {
6174 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
6175 }
6176 // create a CL buffer from image pixel buffer
6177 length = inputImage->columns * inputImage->rows;
6178 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags,
6179 length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
6180 if (clStatus != CL_SUCCESS)
6181 {
6182 (void) ThrowMagickException(exception, GetMagickModule(),
6183 ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
6184 goto cleanup;
6185 }
6186
6187
6188 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,
6189 MagickTrue,exception);
6190 assert(filteredImage != NULL);
6191 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
6192 {
6193 (void) ThrowMagickException(exception, GetMagickModule(),
6194 ResourceLimitError, "CloneImage failed.", "'%s'", ".");
6195 goto cleanup;
6196 }
6197 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
6198 if (filteredPixels == (void *) NULL)
6199 {
6200 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
6201 "UnableToReadPixelCache.","`%s'",filteredImage->filename);
6202 goto cleanup;
6203 }
6204
6205 if (ALIGNED(filteredPixels,CLPixelPacket))
6206 {
6207 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
6208 hostPtr = filteredPixels;
6209 }
6210 else
6211 {
6212 mem_flags = CL_MEM_WRITE_ONLY;
6213 hostPtr = NULL;
6214 }
6215 // create a CL buffer from image pixel buffer
6216 length = inputImage->columns * inputImage->rows;
6217 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags,
6218 length * sizeof(CLPixelPacket), hostPtr, &clStatus);
6219 if (clStatus != CL_SUCCESS)
6220 {
6221 (void) ThrowMagickException(exception, GetMagickModule(),
6222 ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
6223 goto cleanup;
6224 }
6225
6226
6227 imageKernelBuffer = clEnv->library->clCreateBuffer(context,
6228 CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, width * sizeof(float), NULL,
6229 &clStatus);
6230 if (clStatus != CL_SUCCESS)
6231 {
6232 (void) ThrowMagickException(exception, GetMagickModule(),
6233 ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
6234 goto cleanup;
6235 }
6236
6237 queue = AcquireOpenCLCommandQueue(clEnv);
6238 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer,
6239 CL_TRUE, CL_MAP_WRITE, 0, width * sizeof(float), 0, NULL, NULL, &clStatus);
6240 if (clStatus != CL_SUCCESS)
6241 {
6242 (void) ThrowMagickException(exception, GetMagickModule(),
6243 ResourceLimitError, "clEnv->library->clEnqueueMapBuffer failed.",".");
6244 goto cleanup;
6245 }
6246 for (i = 0; i < width; i++)
6247 {
6248 kernelBufferPtr[i] = (float) kernel[i];
6249 }
6250 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr,
6251 0, NULL, NULL);
6252 if (clStatus != CL_SUCCESS)
6253 {
6254 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6255 "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
6256 goto cleanup;
6257 }
6258
6259 offsetBuffer = clEnv->library->clCreateBuffer(context,
6260 CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, width * sizeof(cl_int2), NULL,
6261 &clStatus);
6262 if (clStatus != CL_SUCCESS)
6263 {
6264 (void) ThrowMagickException(exception, GetMagickModule(),
6265 ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
6266 goto cleanup;
6267 }
6268
6269 offsetBufferPtr = (int*)clEnv->library->clEnqueueMapBuffer(queue, offsetBuffer, CL_TRUE,
6270 CL_MAP_WRITE, 0, width * sizeof(cl_int2), 0, NULL, NULL, &clStatus);
6271 if (clStatus != CL_SUCCESS)
6272 {
6273 (void) ThrowMagickException(exception, GetMagickModule(),
6274 ResourceLimitError, "clEnv->library->clEnqueueMapBuffer failed.",".");
6275 goto cleanup;
6276 }
6277 for (i = 0; i < width; i++)
6278 {
6279 offsetBufferPtr[2*i] = (int)offset[i].x;
6280 offsetBufferPtr[2*i+1] = (int)offset[i].y;
6281 }
6282 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, offsetBuffer, offsetBufferPtr, 0,
6283 NULL, NULL);
6284 if (clStatus != CL_SUCCESS)
6285 {
6286 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6287 "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
6288 goto cleanup;
6289 }
6290
6291
6292 // get the OpenCL kernel
6293 motionBlurKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE,
6294 "MotionBlur");
6295 if (motionBlurKernel == NULL)
6296 {
6297 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6298 "AcquireOpenCLKernel failed.", "'%s'", ".");
6299 goto cleanup;
6300 }
6301
6302 // set the kernel arguments
6303 i = 0;
6304 clStatus=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
6305 (void *)&inputImageBuffer);
6306 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
6307 (void *)&filteredImageBuffer);
6308 imageWidth = inputImage->columns;
6309 imageHeight = inputImage->rows;
6310 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int),
6311 &imageWidth);
6312 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int),
6313 &imageHeight);
6314 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
6315 (void *)&imageKernelBuffer);
6316 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int),
6317 &width);
6318 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
6319 (void *)&offsetBuffer);
6320
6321 GetMagickPixelPacket(inputImage,&bias);
6322 biasPixel.s[0] = bias.red;
6323 biasPixel.s[1] = bias.green;
6324 biasPixel.s[2] = bias.blue;
6325 biasPixel.s[3] = bias.opacity;
6326 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_float4), &biasPixel);
6327
6328 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(ChannelType), &channel);
6329 matte = (inputImage->matte == MagickTrue)?1:0;
6330 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int), &matte);
6331 if (clStatus != CL_SUCCESS)
6332 {
6333 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6334 "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
6335 goto cleanup;
6336 }
6337
6338 // launch the kernel
6339 local_work_size[0] = 16;
6340 local_work_size[1] = 16;
6341 global_work_size[0] = (size_t)padGlobalWorkgroupSizeToLocalWorkgroupSize(
6342 inputImage->columns,local_work_size[0]);
6343 global_work_size[1] = (size_t)padGlobalWorkgroupSizeToLocalWorkgroupSize(
6344 inputImage->rows,local_work_size[1]);
6345 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, motionBlurKernel, 2, NULL,
6346 global_work_size, local_work_size, 0, NULL, NULL);
6347
6348 if (clStatus != CL_SUCCESS)
6349 {
6350 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6351 "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
6352 goto cleanup;
6353 }
6354 clEnv->library->clFlush(queue);
6355
6356 if (ALIGNED(filteredPixels,CLPixelPacket))
6357 {
6358 length = inputImage->columns * inputImage->rows;
6359 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE,
6360 CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL,
6361 NULL, &clStatus);
6362 }
6363 else
6364 {
6365 length = inputImage->columns * inputImage->rows;
6366 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0,
6367 length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
6368 }
6369 if (clStatus != CL_SUCCESS)
6370 {
6371 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6372 "Reading output image from CL buffer failed.", "'%s'", ".");
6373 goto cleanup;
6374 }
6375 outputReady = MagickTrue;
6376
6377cleanup:
6378
6379 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
6380 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer);
6381 if (imageKernelBuffer!=NULL) clEnv->library->clReleaseMemObject(imageKernelBuffer);
6382 if (motionBlurKernel!=NULL) RelinquishOpenCLKernel(clEnv, motionBlurKernel);
6383 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
6384 if (outputReady == MagickFalse)
6385 {
6386 if (filteredImage != NULL)
6387 {
6388 DestroyImage(filteredImage);
6389 filteredImage = NULL;
6390 }
6391 }
6392
6393 return filteredImage;
6394}
6395
6396
6397MagickExport
6398Image* AccelerateMotionBlurImage(const Image *image, const ChannelType channel,
6399 const double* kernel, const size_t width, const OffsetInfo *offset,
6400 ExceptionInfo *exception)
6401{
6402 MagickBooleanType status;
6403 Image* filteredImage = NULL;
6404
6405 assert(image != NULL);
6406 assert(kernel != (double *) NULL);
6407 assert(offset != (OffsetInfo *) NULL);
6408 assert(exception != (ExceptionInfo *) NULL);
6409
6410 status = checkOpenCLEnvironment(exception);
6411 if (status == MagickFalse)
6412 return NULL;
6413
6414 status = checkAccelerateCondition(image, channel);
6415 if (status == MagickFalse)
6416 return NULL;
6417
6418 filteredImage = ComputeMotionBlurImage(image, channel, kernel, width,
6419 offset, exception);
6420 return filteredImage;
6421
6422}
6423
6424
6425static MagickBooleanType LaunchCompositeKernel(MagickCLEnv clEnv,
6426 cl_command_queue queue,
6427 cl_mem inputImageBuffer,
6428 const unsigned int inputWidth, const unsigned int inputHeight,
6429 const unsigned int matte,
6430 const ChannelType channel,const CompositeOperator compose,
6431 const cl_mem compositeImageBuffer,
6432 const unsigned int compositeWidth,
6433 const unsigned int compositeHeight,
6434 const float destination_dissolve,const float source_dissolve,
6435 ExceptionInfo *magick_unused(exception))
6436{
6437 size_t global_work_size[2];
6438 size_t local_work_size[2];
6439 unsigned int composeOp;
6440 int k;
6441
6442 cl_int clStatus;
6443 cl_kernel compositeKernel = NULL;
6444
6445 magick_unreferenced(exception);
6446
6447 compositeKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE,
6448 "Composite");
6449
6450 k = 0;
6451 clStatus=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(cl_mem),(void*)&inputImageBuffer);
6452 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&inputWidth);
6453 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&inputHeight);
6454 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(cl_mem),(void*)&compositeImageBuffer);
6455 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&compositeWidth);
6456 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&compositeHeight);
6457 composeOp = (unsigned int)compose;
6458 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&composeOp);
6459 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(ChannelType),(void*)&channel);
6460 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&matte);
6461 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(float),(void*)&destination_dissolve);
6462 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(float),(void*)&source_dissolve);
6463
6464 if (clStatus!=CL_SUCCESS)
6465 return MagickFalse;
6466
6467 local_work_size[0] = 64;
6468 local_work_size[1] = 1;
6469
6470 global_work_size[0] = padGlobalWorkgroupSizeToLocalWorkgroupSize(inputWidth,
6471 local_work_size[0]);
6472 global_work_size[1] = inputHeight;
6473 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, compositeKernel, 2, NULL,
6474 global_work_size, local_work_size, 0, NULL, NULL);
6475
6476
6477 RelinquishOpenCLKernel(clEnv, compositeKernel);
6478
6479 return (clStatus==CL_SUCCESS)?MagickTrue:MagickFalse;
6480}
6481
6482
6483static MagickBooleanType ComputeCompositeImage(Image *inputImage,
6484 const ChannelType channel,const CompositeOperator compose,
6485 const Image *compositeImage,const ssize_t magick_unused(x_offset),const ssize_t magick_unused(y_offset),
6486 const float destination_dissolve,const float source_dissolve,
6487 ExceptionInfo *exception)
6488{
6489 MagickBooleanType status = MagickFalse;
6490
6491 MagickBooleanType outputReady = MagickFalse;
6492 MagickCLEnv clEnv = NULL;
6493
6494 cl_int clStatus;
6495
6496 void *inputPixels = NULL;
6497 const void *composePixels = NULL;
6498 MagickSizeType length;
6499
6500 cl_mem_flags mem_flags;
6501 cl_context context = NULL;
6502 cl_mem inputImageBuffer = NULL;
6503 cl_mem compositeImageBuffer = NULL;
6504 cl_command_queue queue = NULL;
6505
6506 magick_unreferenced(x_offset);
6507 magick_unreferenced(y_offset);
6508
6509 clEnv = GetDefaultOpenCLEnv();
6510 context = GetOpenCLContext(clEnv);
6511 queue = AcquireOpenCLCommandQueue(clEnv);
6512
6513 /* Create and initialize OpenCL buffers. */
6514 inputPixels = GetPixelCachePixels(inputImage, &length, exception);
6515 if (inputPixels == (void *) NULL)
6516 {
6517 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,
6518 "UnableToReadPixelCache.","`%s'",inputImage->filename);
6519 goto cleanup;
6520 }
6521
6522 /* If the host pointer is aligned to the size of CLPixelPacket,
6523 then use the host buffer directly from the GPU; otherwise,
6524 create a buffer on the GPU and copy the data over */
6525 if (ALIGNED(inputPixels,CLPixelPacket))
6526 {
6527 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
6528 }
6529 else
6530 {
6531 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
6532 }
6533 /* create a CL buffer from image pixel buffer */
6534 length = inputImage->columns * inputImage->rows;
6535 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags,
6536 length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
6537 if (clStatus != CL_SUCCESS)
6538 {
6539 (void) OpenCLThrowMagickException(exception, GetMagickModule(),
6540 ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
6541 goto cleanup;
6542 }
6543
6544
6545 /* Create and initialize OpenCL buffers. */
6546 composePixels = AcquirePixelCachePixels(compositeImage, &length, exception);
6547 if (composePixels == (void *) NULL)
6548 {
6549 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,
6550 "UnableToReadPixelCache.","`%s'",compositeImage->filename);
6551 goto cleanup;
6552 }
6553
6554 /* If the host pointer is aligned to the size of CLPixelPacket,
6555 then use the host buffer directly from the GPU; otherwise,
6556 create a buffer on the GPU and copy the data over */
6557 if (ALIGNED(composePixels,CLPixelPacket))
6558 {
6559 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
6560 }
6561 else
6562 {
6563 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
6564 }
6565 /* create a CL buffer from image pixel buffer */
6566 length = compositeImage->columns * compositeImage->rows;
6567 compositeImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags,
6568 length * sizeof(CLPixelPacket), (void*)composePixels, &clStatus);
6569 if (clStatus != CL_SUCCESS)
6570 {
6571 (void) OpenCLThrowMagickException(exception, GetMagickModule(),
6572 ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
6573 goto cleanup;
6574 }
6575
6576 status = LaunchCompositeKernel(clEnv,queue,inputImageBuffer,
6577 (unsigned int) inputImage->columns,
6578 (unsigned int) inputImage->rows,
6579 (unsigned int) inputImage->matte,
6580 channel, compose, compositeImageBuffer,
6581 (unsigned int) compositeImage->columns,
6582 (unsigned int) compositeImage->rows,
6583 destination_dissolve,source_dissolve,
6584 exception);
6585
6586 if (status==MagickFalse)
6587 goto cleanup;
6588
6589 length = inputImage->columns * inputImage->rows;
6590 if (ALIGNED(inputPixels,CLPixelPacket))
6591 {
6592 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE,
6593 CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL,
6594 NULL, &clStatus);
6595 }
6596 else
6597 {
6598 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0,
6599 length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
6600 }
6601 if (clStatus==CL_SUCCESS)
6602 outputReady = MagickTrue;
6603
6604cleanup:
6605 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer);
6606 if (compositeImageBuffer!=NULL) clEnv->library->clReleaseMemObject(compositeImageBuffer);
6607 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
6608
6609 return outputReady;
6610}
6611
6612
6613MagickExport
6614MagickBooleanType AccelerateCompositeImage(Image *image,
6615 const ChannelType channel,const CompositeOperator compose,
6616 const Image *composite,const ssize_t x_offset,const ssize_t y_offset,
6617 const float destination_dissolve,const float source_dissolve,
6618 ExceptionInfo *exception)
6619{
6620 MagickBooleanType status;
6621
6622 assert(image != NULL);
6623 assert(composite != NULL);
6624 assert(exception != (ExceptionInfo *) NULL);
6625
6626 status = checkOpenCLEnvironment(exception);
6627 if (status == MagickFalse)
6628 return MagickFalse;
6629
6630 status = checkAccelerateCondition(image, channel);
6631 if (status == MagickFalse)
6632 return MagickFalse;
6633
6634 /* only support zero offset and
6635 images with the size for now */
6636 if (x_offset!=0
6637 || y_offset!=0
6638 || image->columns!=composite->columns
6639 || image->rows!=composite->rows)
6640 return MagickFalse;
6641
6642 switch(compose) {
6643 case ColorDodgeCompositeOp:
6644 case BlendCompositeOp:
6645 break;
6646 default:
6647 // unsupported compose operator, quit
6648 return MagickFalse;
6649 };
6650
6651 status = ComputeCompositeImage(image,channel,compose,composite,
6652 x_offset,y_offset,destination_dissolve,source_dissolve,exception);
6653
6654 return status;
6655}
6656
6657
cristye85d0f72013-11-27 02:25:43 +00006658
cristyf034abb2013-11-24 14:16:14 +00006659#else /* MAGICKCORE_OPENCL_SUPPORT */
6660
6661MagickExport Image *AccelerateConvolveImageChannel(
6662 const Image *magick_unused(image),const ChannelType magick_unused(channel),
6663 const KernelInfo *magick_unused(kernel),
6664 ExceptionInfo *magick_unused(exception))
6665{
6666 magick_unreferenced(image);
6667 magick_unreferenced(channel);
6668 magick_unreferenced(kernel);
6669 magick_unreferenced(exception);
6670
6671 return NULL;
6672}
6673
6674MagickExport MagickBooleanType AccelerateFunctionImage(
6675 Image *magick_unused(image),const ChannelType magick_unused(channel),
6676 const MagickFunction magick_unused(function),
6677 const size_t magick_unused(number_parameters),
6678 const double *magick_unused(parameters),
6679 ExceptionInfo *magick_unused(exception))
6680{
6681 magick_unreferenced(image);
6682 magick_unreferenced(channel);
6683 magick_unreferenced(function);
6684 magick_unreferenced(number_parameters);
6685 magick_unreferenced(parameters);
6686 magick_unreferenced(exception);
6687
6688 return MagickFalse;
6689}
6690
6691MagickExport Image *AccelerateBlurImage(const Image *magick_unused(image),
6692 const ChannelType magick_unused(channel),const double magick_unused(radius),
6693 const double magick_unused(sigma),ExceptionInfo *magick_unused(exception))
6694{
6695 magick_unreferenced(image);
6696 magick_unreferenced(channel);
6697 magick_unreferenced(radius);
6698 magick_unreferenced(sigma);
6699 magick_unreferenced(exception);
6700
6701 return NULL;
6702}
6703
6704MagickExport Image *AccelerateRadialBlurImage(
6705 const Image *magick_unused(image),const ChannelType magick_unused(channel),
6706 const double magick_unused(angle),ExceptionInfo *magick_unused(exception))
6707{
6708 magick_unreferenced(image);
6709 magick_unreferenced(channel);
6710 magick_unreferenced(angle);
6711 magick_unreferenced(exception);
6712
6713 return NULL;
6714}
6715
6716
6717MagickExport Image *AccelerateUnsharpMaskImage(
6718 const Image *magick_unused(image),const ChannelType magick_unused(channel),
6719 const double magick_unused(radius),const double magick_unused(sigma),
6720 const double magick_unused(gain),const double magick_unused(threshold),
6721 ExceptionInfo *magick_unused(exception))
6722{
6723 magick_unreferenced(image);
6724 magick_unreferenced(channel);
6725 magick_unreferenced(radius);
6726 magick_unreferenced(sigma);
6727 magick_unreferenced(gain);
6728 magick_unreferenced(threshold);
6729 magick_unreferenced(exception);
6730
6731 return NULL;
6732}
6733
6734
6735MagickExport MagickBooleanType AccelerateContrastImage(
6736 Image* magick_unused(image),const MagickBooleanType magick_unused(sharpen),
6737 ExceptionInfo* magick_unused(exception))
6738{
6739 magick_unreferenced(image);
6740 magick_unreferenced(sharpen);
6741 magick_unreferenced(exception);
6742
6743 return MagickFalse;
6744}
6745
cristy0c832c62014-03-07 22:21:04 +00006746MagickExport MagickBooleanType AcceleratContrastStretchImageChannel(
6747 Image * image, const ChannelType channel, const double black_point, const double white_point,
6748 ExceptionInfo* magick_unused(exception))
6749{
6750 magick_unreferenced(image);
6751 magick_unreferenced(channel);
6752 magick_unreferenced(black_point);
6753 magick_unreferenced(white_point);
6754 magick_unreferenced(exception);
6755
6756 return MagickFalse;
6757}
6758
cristyf034abb2013-11-24 14:16:14 +00006759MagickExport MagickBooleanType AccelerateEqualizeImage(
6760 Image* magick_unused(image), const ChannelType magick_unused(channel),
6761 ExceptionInfo* magick_unused(exception))
6762{
6763 magick_unreferenced(image);
6764 magick_unreferenced(channel);
6765 magick_unreferenced(exception);
6766
6767 return MagickFalse;
6768}
6769
6770MagickExport Image *AccelerateDespeckleImage(const Image* magick_unused(image),
6771 ExceptionInfo* magick_unused(exception))
6772{
6773 magick_unreferenced(image);
6774 magick_unreferenced(exception);
6775
6776 return NULL;
6777}
6778
6779MagickExport Image *AccelerateResizeImage(const Image* magick_unused(image),
6780 const size_t magick_unused(resizedColumns),
6781 const size_t magick_unused(resizedRows),
6782 const ResizeFilter* magick_unused(resizeFilter),
6783 ExceptionInfo *magick_unused(exception))
6784{
6785 magick_unreferenced(image);
6786 magick_unreferenced(resizedColumns);
6787 magick_unreferenced(resizedRows);
6788 magick_unreferenced(resizeFilter);
6789 magick_unreferenced(exception);
6790
6791 return NULL;
6792}
6793
cristyf034abb2013-11-24 14:16:14 +00006794MagickExport
6795MagickBooleanType AccelerateModulateImage(
6796 Image* image, double percent_brightness, double percent_hue,
6797 double percent_saturation, ColorspaceType colorspace, ExceptionInfo* exception)
6798{
6799 magick_unreferenced(image);
6800 magick_unreferenced(percent_brightness);
6801 magick_unreferenced(percent_hue);
6802 magick_unreferenced(percent_saturation);
6803 magick_unreferenced(colorspace);
6804 magick_unreferenced(exception);
6805 return(MagickFalse);
6806}
6807
cristy0c832c62014-03-07 22:21:04 +00006808MagickExport
6809MagickBooleanType AccelerateNegateImageChannel(
6810 Image* image, const ChannelType channel, const MagickBooleanType grayscale, ExceptionInfo* exception)
6811{
6812 magick_unreferenced(image);
6813 magick_unreferenced(channel);
6814 magick_unreferenced(grayscale);
6815 magick_unreferenced(exception);
6816 return(MagickFalse);
6817}
6818
6819MagickExport
6820MagickBooleanType AccelerateGrayscaleImage(
6821 Image* image, const PixelIntensityMethod method, ExceptionInfo* exception)
6822{
6823 magick_unreferenced(image);
6824 magick_unreferenced(method);
6825 magick_unreferenced(exception);
6826 return(MagickFalse);
6827}
6828
cristye85d0f72013-11-27 02:25:43 +00006829MagickExport Image *AccelerateAddNoiseImage(const Image *image,
6830 const ChannelType channel, const NoiseType noise_type,ExceptionInfo *exception)
6831{
6832 magick_unreferenced(image);
6833 magick_unreferenced(channel);
6834 magick_unreferenced(noise_type);
6835 magick_unreferenced(exception);
6836 return NULL;
6837}
cristyf034abb2013-11-24 14:16:14 +00006838
cristy0c832c62014-03-07 22:21:04 +00006839
6840MagickExport MagickBooleanType AccelerateRandomImage(Image* image, ExceptionInfo* exception)
6841{
6842 magick_unreferenced(image);
6843 magick_unreferenced(exception);
6844 return MagickFalse;
6845}
6846
6847MagickExport
6848Image* AccelerateMotionBlurImage(const Image *image, const ChannelType channel,
6849 const double* kernel, const size_t width,
6850 const OffsetInfo *offset,
6851 ExceptionInfo *exception)
6852{
6853 magick_unreferenced(image);
6854 magick_unreferenced(channel);
6855 magick_unreferenced(kernel);
6856 magick_unreferenced(width);
6857 magick_unreferenced(offset);
6858 magick_unreferenced(exception);
6859 return NULL;
6860}
6861
cristyf034abb2013-11-24 14:16:14 +00006862#endif /* MAGICKCORE_OPENCL_SUPPORT */
6863
6864MagickExport MagickBooleanType AccelerateConvolveImage(
6865 const Image *magick_unused(image),const KernelInfo *magick_unused(kernel),
6866 Image *magick_unused(convolve_image),ExceptionInfo *magick_unused(exception))
6867{
6868 magick_unreferenced(image);
6869 magick_unreferenced(kernel);
6870 magick_unreferenced(convolve_image);
6871 magick_unreferenced(exception);
6872
6873 /* legacy, do not use */
6874 return(MagickFalse);
6875}
6876