MagickCore  6.7.5
accelerate.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %     AAA     CCCC    CCCC  EEEEE  L      EEEEE  RRRR    AAA   TTTTT  EEEEE   %
00007 %    A   A   C       C      E      L      E      R   R  A   A    T    E       %
00008 %    AAAAA   C       C      EEE    L      EEE    RRRR   AAAAA    T    EEE     %
00009 %    A   A   C       C      E      L      E      R R    A   A    T    E       %
00010 %    A   A    CCCC    CCCC  EEEEE  LLLLL  EEEEE  R  R   A   A    T    EEEEE   %
00011 %                                                                             %
00012 %                                                                             %
00013 %                       MagickCore Acceleration Methods                       %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                               John Cristy                                   %
00017 %                               January 2010                                  %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 % Morphology is the the application of various kernals, of any size and even
00037 % shape, to a image in various ways (typically binary, but not always).
00038 %
00039 % Convolution (weighted sum or average) is just one specific type of
00040 % accelerate. Just one that is very common for image bluring and sharpening
00041 % effects.  Not only 2D Gaussian blurring, but also 2-pass 1D Blurring.
00042 %
00043 % This module provides not only a general accelerate function, and the ability
00044 % to apply more advanced or iterative morphologies, but also functions for the
00045 % generation of many different types of kernel arrays from user supplied
00046 % arguments. Prehaps even the generation of a kernel from a small image.
00047 */
00048 
00049 /*
00050   Include declarations.
00051 */
00052 #include "MagickCore/studio.h"
00053 #include "MagickCore/accelerate.h"
00054 #include "MagickCore/artifact.h"
00055 #include "MagickCore/cache.h"
00056 #include "MagickCore/cache-private.h"
00057 #include "MagickCore/cache-view.h"
00058 #include "MagickCore/color-private.h"
00059 #include "MagickCore/enhance.h"
00060 #include "MagickCore/exception.h"
00061 #include "MagickCore/exception-private.h"
00062 #include "MagickCore/gem.h"
00063 #include "MagickCore/hashmap.h"
00064 #include "MagickCore/image.h"
00065 #include "MagickCore/image-private.h"
00066 #include "MagickCore/list.h"
00067 #include "MagickCore/memory_.h"
00068 #include "MagickCore/monitor-private.h"
00069 #include "MagickCore/accelerate.h"
00070 #include "MagickCore/option.h"
00071 #include "MagickCore/pixel-accessor.h"
00072 #include "MagickCore/prepress.h"
00073 #include "MagickCore/quantize.h"
00074 #include "MagickCore/registry.h"
00075 #include "MagickCore/semaphore.h"
00076 #include "MagickCore/splay-tree.h"
00077 #include "MagickCore/statistic.h"
00078 #include "MagickCore/string_.h"
00079 #include "MagickCore/string-private.h"
00080 #include "MagickCore/token.h"
00081 
00082 /*
00083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00084 %                                                                             %
00085 %                                                                             %
00086 %                                                                             %
00087 %     A c c e l e r a t e C o n v o l v e I m a g e                           %
00088 %                                                                             %
00089 %                                                                             %
00090 %                                                                             %
00091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00092 %
00093 %  AccelerateConvolveImage() applies a custom convolution kernel to the image.
00094 %  It is accelerated by taking advantage of speed-ups offered by executing in
00095 %  concert across heterogeneous platforms consisting of CPUs, GPUs, and other
00096 %  processors.
00097 %
00098 %  The format of the AccelerateConvolveImage method is:
00099 %
00100 %      Image *AccelerateConvolveImage(const Image *image,
00101 %        const KernelInfo *kernel,Image *convolve_image,
00102 %        ExceptionInfo *exception)
00103 %
00104 %  A description of each parameter follows:
00105 %
00106 %    o image: the image.
00107 %
00108 %    o kernel: the convolution kernel.
00109 %
00110 %    o convole_image: the convoleed image.
00111 %
00112 %    o exception: return any errors or warnings in this structure.
00113 %
00114 */
00115 
00116 #if defined(MAGICKCORE_OPENCL_SUPPORT)
00117 
00118 #if defined(MAGICKCORE_HDRI_SUPPORT)
00119 #define CLOptions "-DMAGICKCORE_HDRI_SUPPORT=1 -DCLQuantum=float " \
00120   "-DCLPixelType=float4 -DQuantumRange=%g -DMagickEpsilon=%g"
00121 #define CLPixelInfo  cl_float4
00122 #else
00123 #if (MAGICKCORE_QUANTUM_DEPTH == 8)
00124 #define CLOptions "-DCLQuantum=uchar -DCLPixelType=uchar4 " \
00125   "-DQuantumRange=%g -DMagickEpsilon=%g"
00126 #define CLPixelInfo  cl_uchar4
00127 #elif (MAGICKCORE_QUANTUM_DEPTH == 16)
00128 #define CLOptions "-DCLQuantum=ushort -DCLPixelType=ushort4 " \
00129   "-DQuantumRange=%g -DMagickEpsilon=%g"
00130 #define CLPixelInfo  cl_ushort4
00131 #elif (MAGICKCORE_QUANTUM_DEPTH == 32)
00132 #define CLOptions "-DCLQuantum=uint -DCLPixelType=uint4 " \
00133   "-DQuantumRange=%g -DMagickEpsilon=%g"
00134 #define CLPixelInfo  cl_uint4
00135 #elif (MAGICKCORE_QUANTUM_DEPTH == 64)
00136 #define CLOptions "-DCLQuantum=ussize_t -DCLPixelType=ussize_t4 " \
00137   "-DQuantumRange=%g -DMagickEpsilon=%g"
00138 #define CLPixelInfo  cl_ulong4
00139 #endif
00140 #endif
00141 
00142 typedef struct _ConvolveInfo
00143 {
00144   cl_context
00145     context;
00146 
00147   cl_device_id
00148     *devices;
00149 
00150   cl_command_queue
00151     command_queue;
00152 
00153   cl_kernel
00154     kernel;
00155 
00156   cl_program
00157     program;
00158 
00159   cl_mem
00160     pixels,
00161     convolve_pixels;
00162 
00163   cl_ulong
00164     width,
00165     height;
00166 
00167   cl_uint
00168     matte;
00169 
00170   cl_mem
00171     filter;
00172 } ConvolveInfo;
00173 
00174 static const char
00175   *ConvolveKernel =
00176     "static inline long ClampToCanvas(const long offset,const unsigned long range)\n"
00177     "{\n"
00178     "  if (offset < 0L)\n"
00179     "    return(0L);\n"
00180     "  if (offset >= range)\n"
00181     "    return((long) (range-1L));\n"
00182     "  return(offset);\n"
00183     "}\n"
00184     "\n"
00185     "static inline CLQuantum ClampToQuantum(const float value)\n"
00186     "{\n"
00187     "#if defined(MAGICKCORE_HDRI_SUPPORT)\n"
00188     "  return((CLQuantum) value);\n"
00189     "#else\n"
00190     "  if (value < 0.0)\n"
00191     "    return((CLQuantum) 0);\n"
00192     "  if (value >= (float) QuantumRange)\n"
00193     "    return((CLQuantum) QuantumRange);\n"
00194     "  return((CLQuantum) (value+0.5));\n"
00195     "#endif\n"
00196     "}\n"
00197     "\n"
00198     "__kernel void Convolve(const __global CLPixelType *input,\n"
00199     "  __constant float *filter,const unsigned long width,const unsigned long height,\n"
00200     "  const unsigned int matte,__global CLPixelType *output)\n"
00201     "{\n"
00202     "  const unsigned long columns = get_global_size(0);\n"
00203     "  const unsigned long rows = get_global_size(1);\n"
00204     "\n"
00205     "  const long x = get_global_id(0);\n"
00206     "  const long y = get_global_id(1);\n"
00207     "\n"
00208     "  const float scale = (1.0/QuantumRange);\n"
00209     "  const long mid_width = (width-1)/2;\n"
00210     "  const long mid_height = (height-1)/2;\n"
00211     "  float4 sum = { 0.0, 0.0, 0.0, 0.0 };\n"
00212     "  float gamma = 0.0;\n"
00213     "  register unsigned long i = 0;\n"
00214     "\n"
00215     "  int method = 0;\n"
00216     "  if (matte != false)\n"
00217     "    method=1;\n"
00218     "  if ((x >= width) && (x < (columns-width-1)) &&\n"
00219     "      (y >= height) && (y < (rows-height-1)))\n"
00220     "    {\n"
00221     "      method=2;\n"
00222     "      if (matte != false)\n"
00223     "        method=3;\n"
00224     "    }\n"
00225     "  switch (method)\n"
00226     "  {\n"
00227     "    case 0:\n"
00228     "    {\n"
00229     "      for (long v=(-mid_height); v <= mid_height; v++)\n"
00230     "      {\n"
00231     "        for (long u=(-mid_width); u <= mid_width; u++)\n"
00232     "        {\n"
00233     "          const long index=ClampToCanvas(y+v,rows)*columns+\n"
00234     "            ClampToCanvas(x+u,columns);\n"
00235     "          sum.x+=filter[i]*input[index].x;\n"
00236     "          sum.y+=filter[i]*input[index].y;\n"
00237     "          sum.z+=filter[i]*input[index].z;\n"
00238     "          gamma+=filter[i];\n"
00239     "          i++;\n"
00240     "        }\n"
00241     "      }\n"
00242     "      break;\n"
00243     "    }\n"
00244     "    case 1:\n"
00245     "    {\n"
00246     "      for (long v=(-mid_height); v <= mid_height; v++)\n"
00247     "      {\n"
00248     "        for (long u=(-mid_width); u <= mid_width; u++)\n"
00249     "        {\n"
00250     "          const unsigned long index=ClampToCanvas(y+v,rows)*columns+\n"
00251     "            ClampToCanvas(x+u,columns);\n"
00252     "          const float alpha=scale*input[index].w;\n"
00253     "          sum.x+=alpha*filter[i]*input[index].x;\n"
00254     "          sum.y+=alpha*filter[i]*input[index].y;\n"
00255     "          sum.z+=alpha*filter[i]*input[index].z;\n"
00256     "          sum.w+=filter[i]*input[index].w;\n"
00257     "          gamma+=alpha*filter[i];\n"
00258     "          i++;\n"
00259     "        }\n"
00260     "      }\n"
00261     "      break;\n"
00262     "    }\n"
00263     "    case 2:\n"
00264     "    {\n"
00265     "      for (long v=(-mid_height); v <= mid_height; v++)\n"
00266     "      {\n"
00267     "        for (long u=(-mid_width); u <= mid_width; u++)\n"
00268     "        {\n"
00269     "          const unsigned long index=(y+v)*columns+(x+u);\n"
00270     "          sum.x+=filter[i]*input[index].x;\n"
00271     "          sum.y+=filter[i]*input[index].y;\n"
00272     "          sum.z+=filter[i]*input[index].z;\n"
00273     "          gamma+=filter[i];\n"
00274     "          i++;\n"
00275     "        }\n"
00276     "      }\n"
00277     "      break;\n"
00278     "    }\n"
00279     "    case 3:\n"
00280     "    {\n"
00281     "      for (long v=(-mid_height); v <= mid_height; v++)\n"
00282     "      {\n"
00283     "        for (long u=(-mid_width); u <= mid_width; u++)\n"
00284     "        {\n"
00285     "          const unsigned long index=(y+v)*columns+(x+u);\n"
00286     "          const float alpha=scale*input[index].w;\n"
00287     "          sum.x+=alpha*filter[i]*input[index].x;\n"
00288     "          sum.y+=alpha*filter[i]*input[index].y;\n"
00289     "          sum.z+=alpha*filter[i]*input[index].z;\n"
00290     "          sum.w+=filter[i]*input[index].w;\n"
00291     "          gamma+=alpha*filter[i];\n"
00292     "          i++;\n"
00293     "        }\n"
00294     "      }\n"
00295     "      break;\n"
00296     "    }\n"
00297     "  }\n"
00298     "  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);\n"
00299     "  const unsigned long index = y*columns+x;\n"
00300     "  output[index].x=ClampToQuantum(gamma*sum.x);\n"
00301     "  output[index].y=ClampToQuantum(gamma*sum.y);\n"
00302     "  output[index].z=ClampToQuantum(gamma*sum.z);\n"
00303     "  if (matte == false)\n"
00304     "    output[index].w=input[index].w;\n"
00305     "  else\n"
00306     "    output[index].w=ClampToQuantum(sum.w);\n"
00307     "}\n";
00308 
00309 static void ConvolveNotify(const char *message,const void *data,size_t length,
00310   void *user_context)
00311 {
00312   ExceptionInfo
00313     *exception;
00314 
00315   (void) data;
00316   (void) length;
00317   exception=(ExceptionInfo *) user_context;
00318   (void) ThrowMagickException(exception,GetMagickModule(),DelegateWarning,
00319     "DelegateFailed","`%s'",message);
00320 }
00321 
00322 static MagickBooleanType BindConvolveParameters(ConvolveInfo *convolve_info,
00323   const Image *image,const void *pixels,float *filter,const size_t width,
00324   const size_t height,void *convolve_pixels)
00325 {
00326   cl_int
00327     status;
00328 
00329   register cl_uint
00330     i;
00331 
00332   size_t
00333     length;
00334 
00335   /*
00336     Allocate OpenCL buffers.
00337   */
00338   length=image->columns*image->rows;
00339   convolve_info->pixels=clCreateBuffer(convolve_info->context,(cl_mem_flags)
00340     (CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR),length*sizeof(CLPixelInfo),
00341     (void *) pixels,&status);
00342   if ((convolve_info->pixels == (cl_mem) NULL) || (status != CL_SUCCESS))
00343     return(MagickFalse);
00344   length=width*height;
00345   convolve_info->filter=clCreateBuffer(convolve_info->context,(cl_mem_flags)
00346     (CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR),length*sizeof(cl_float),filter,
00347     &status);
00348   if ((convolve_info->filter == (cl_mem) NULL) || (status != CL_SUCCESS))
00349     return(MagickFalse);
00350   length=image->columns*image->rows;
00351   convolve_info->convolve_pixels=clCreateBuffer(convolve_info->context,
00352     (cl_mem_flags) (CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR),length*
00353     sizeof(CLPixelInfo),convolve_pixels,&status);
00354   if ((convolve_info->convolve_pixels == (cl_mem) NULL) ||
00355       (status != CL_SUCCESS))
00356     return(MagickFalse);
00357   /*
00358     Bind OpenCL buffers.
00359   */
00360   i=0;
00361   status=clSetKernelArg(convolve_info->kernel,i++,sizeof(cl_mem),(void *)
00362     &convolve_info->pixels);
00363   if (status != CL_SUCCESS)
00364     return(MagickFalse);
00365   status=clSetKernelArg(convolve_info->kernel,i++,sizeof(cl_mem),(void *)
00366     &convolve_info->filter);
00367   if (status != CL_SUCCESS)
00368     return(MagickFalse);
00369   convolve_info->width=(cl_ulong) width;
00370   status=clSetKernelArg(convolve_info->kernel,i++,sizeof(cl_ulong),(void *)
00371     &convolve_info->width);
00372   if (status != CL_SUCCESS)
00373     return(MagickFalse);
00374   convolve_info->height=(cl_ulong) height;
00375   status=clSetKernelArg(convolve_info->kernel,i++,sizeof(cl_ulong),(void *)
00376     &convolve_info->height);
00377   if (status != CL_SUCCESS)
00378     return(MagickFalse);
00379   convolve_info->matte=(cl_uint) image->matte;
00380   status=clSetKernelArg(convolve_info->kernel,i++,sizeof(cl_uint),(void *)
00381     &convolve_info->matte);
00382   if (status != CL_SUCCESS)
00383     return(MagickFalse);
00384   status=clSetKernelArg(convolve_info->kernel,i++,sizeof(cl_mem),(void *)
00385     &convolve_info->convolve_pixels);
00386   if (status != CL_SUCCESS)
00387     return(MagickFalse);
00388   status=clFinish(convolve_info->command_queue);
00389   if (status != CL_SUCCESS)
00390     return(MagickFalse);
00391   return(MagickTrue);
00392 }
00393 
00394 static void DestroyConvolveBuffers(ConvolveInfo *convolve_info)
00395 {
00396   cl_int
00397     status;
00398 
00399   status=0;
00400   if (convolve_info->convolve_pixels != (cl_mem) NULL)
00401     status=clReleaseMemObject(convolve_info->convolve_pixels);
00402   if (convolve_info->pixels != (cl_mem) NULL)
00403     status=clReleaseMemObject(convolve_info->pixels);
00404   if (convolve_info->filter != (cl_mem) NULL)
00405     status=clReleaseMemObject(convolve_info->filter);
00406   (void) status;
00407 }
00408 
00409 static ConvolveInfo *DestroyConvolveInfo(ConvolveInfo *convolve_info)
00410 {
00411   cl_int
00412     status;
00413 
00414   status=0;
00415   if (convolve_info->kernel != (cl_kernel) NULL)
00416     status=clReleaseKernel(convolve_info->kernel);
00417   if (convolve_info->program != (cl_program) NULL)
00418     status=clReleaseProgram(convolve_info->program);
00419   if (convolve_info->command_queue != (cl_command_queue) NULL)
00420     status=clReleaseCommandQueue(convolve_info->command_queue);
00421   if (convolve_info->context != (cl_context) NULL)
00422     status=clReleaseContext(convolve_info->context);
00423   (void) status;
00424   convolve_info=(ConvolveInfo *) RelinquishMagickMemory(convolve_info);
00425   return(convolve_info);
00426 }
00427 
00428 static MagickBooleanType EnqueueConvolveKernel(ConvolveInfo *convolve_info,
00429   const Image *image,const void *pixels,float *filter,const size_t width,
00430   const size_t height,void *convolve_pixels)
00431 {
00432   cl_int
00433     status;
00434 
00435   size_t
00436     global_work_size[2],
00437     length;
00438 
00439   length=image->columns*image->rows;
00440   status=clEnqueueWriteBuffer(convolve_info->command_queue,
00441     convolve_info->pixels,CL_TRUE,0,length*sizeof(CLPixelInfo),pixels,0,NULL,
00442     NULL);
00443   length=width*height;
00444   status=clEnqueueWriteBuffer(convolve_info->command_queue,
00445     convolve_info->filter,CL_TRUE,0,length*sizeof(cl_float),filter,0,NULL,
00446     NULL);
00447   if (status != CL_SUCCESS)
00448     return(MagickFalse);
00449   global_work_size[0]=image->columns;
00450   global_work_size[1]=image->rows;
00451   status=clEnqueueNDRangeKernel(convolve_info->command_queue,
00452     convolve_info->kernel,2,NULL,global_work_size,NULL,0,NULL,NULL);
00453   if (status != CL_SUCCESS)
00454     return(MagickFalse);
00455   length=image->columns*image->rows;
00456   status=clEnqueueReadBuffer(convolve_info->command_queue,
00457     convolve_info->convolve_pixels,CL_TRUE,0,length*sizeof(CLPixelInfo),
00458     convolve_pixels,0,NULL,NULL);
00459   if (status != CL_SUCCESS)
00460     return(MagickFalse);
00461   status=clFinish(convolve_info->command_queue);
00462   if (status != CL_SUCCESS)
00463     return(MagickFalse);
00464   return(MagickTrue);
00465 }
00466 
00467 static ConvolveInfo *GetConvolveInfo(const Image *image,const char *name,
00468   const char *source,ExceptionInfo *exception)
00469 {
00470   char
00471     options[MaxTextExtent];
00472 
00473   cl_context_properties
00474     context_properties[3];
00475 
00476   cl_int
00477     status;
00478 
00479   cl_platform_id
00480     platforms[1];
00481 
00482   cl_uint
00483     number_platforms;
00484 
00485   ConvolveInfo
00486     *convolve_info;
00487 
00488   size_t
00489     length,
00490     lengths[] = { strlen(source) };
00491 
00492   /*
00493     Create OpenCL info.
00494   */
00495   convolve_info=(ConvolveInfo *) AcquireMagickMemory(sizeof(*convolve_info));
00496   if (convolve_info == (ConvolveInfo *) NULL)
00497     {
00498       (void) ThrowMagickException(exception,GetMagickModule(),
00499         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
00500       return((ConvolveInfo *) NULL);
00501     }
00502   (void) ResetMagickMemory(convolve_info,0,sizeof(*convolve_info));
00503   /*
00504     Create OpenCL context.
00505   */
00506   status=clGetPlatformIDs(0,(cl_platform_id *) NULL,&number_platforms);
00507   if ((status == CL_SUCCESS) && (number_platforms > 0))
00508     status=clGetPlatformIDs(1,platforms,NULL);
00509   if (status != CL_SUCCESS)
00510     {
00511       (void) ThrowMagickException(exception,GetMagickModule(),DelegateWarning,
00512         "failed to create OpenCL context","`%s' (%d)",image->filename,status);
00513       convolve_info=DestroyConvolveInfo(convolve_info);
00514       return((ConvolveInfo *) NULL);
00515     }
00516   context_properties[0]=CL_CONTEXT_PLATFORM;
00517   context_properties[1]=(cl_context_properties) platforms[0];
00518   context_properties[2]=0;
00519   convolve_info->context=clCreateContextFromType(context_properties,
00520     (cl_device_type) CL_DEVICE_TYPE_GPU,ConvolveNotify,exception,&status);
00521   if ((convolve_info->context == (cl_context) NULL) || (status != CL_SUCCESS))
00522     convolve_info->context=clCreateContextFromType(context_properties,
00523       (cl_device_type) CL_DEVICE_TYPE_CPU,ConvolveNotify,exception,&status);
00524   if ((convolve_info->context == (cl_context) NULL) || (status != CL_SUCCESS))
00525     convolve_info->context=clCreateContextFromType(context_properties,
00526       (cl_device_type) CL_DEVICE_TYPE_DEFAULT,ConvolveNotify,exception,&status);
00527   if ((convolve_info->context == (cl_context) NULL) || (status != CL_SUCCESS))
00528     {
00529       (void) ThrowMagickException(exception,GetMagickModule(),DelegateWarning,
00530         "failed to create OpenCL context","`%s' (%d)",image->filename,status);
00531       convolve_info=DestroyConvolveInfo(convolve_info);
00532       return((ConvolveInfo *) NULL);
00533     }
00534   /*
00535     Detect OpenCL devices.
00536   */
00537   status=clGetContextInfo(convolve_info->context,CL_CONTEXT_DEVICES,0,NULL,
00538     &length);
00539   if ((status != CL_SUCCESS) || (length == 0))
00540     {
00541       convolve_info=DestroyConvolveInfo(convolve_info);
00542       return((ConvolveInfo *) NULL);
00543     }
00544   convolve_info->devices=(cl_device_id *) AcquireMagickMemory(length);
00545   if (convolve_info->devices == (cl_device_id *) NULL)
00546     {
00547       (void) ThrowMagickException(exception,GetMagickModule(),
00548         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
00549       convolve_info=DestroyConvolveInfo(convolve_info);
00550       return((ConvolveInfo *) NULL);
00551     }
00552   status=clGetContextInfo(convolve_info->context,CL_CONTEXT_DEVICES,length,
00553     convolve_info->devices,NULL);
00554   if (status != CL_SUCCESS)
00555     {
00556       convolve_info=DestroyConvolveInfo(convolve_info);
00557       return((ConvolveInfo *) NULL);
00558     }
00559   if (image->debug != MagickFalse)
00560     {
00561       char
00562         attribute[MaxTextExtent];
00563 
00564       size_t
00565         length;
00566 
00567       clGetDeviceInfo(convolve_info->devices[0],CL_DEVICE_NAME,
00568         sizeof(attribute),attribute,&length);
00569       (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),"Name: %s",
00570         attribute);
00571       clGetDeviceInfo(convolve_info->devices[0],CL_DEVICE_VENDOR,
00572         sizeof(attribute),attribute,&length);
00573       (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),"Vendor: %s",
00574         attribute);
00575       clGetDeviceInfo(convolve_info->devices[0],CL_DEVICE_VERSION,
00576         sizeof(attribute),attribute,&length);
00577       (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
00578         "Driver Version: %s",attribute);
00579       clGetDeviceInfo(convolve_info->devices[0],CL_DEVICE_PROFILE,
00580         sizeof(attribute),attribute,&length);
00581       (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),"Profile: %s",
00582         attribute);
00583       clGetDeviceInfo(convolve_info->devices[0],CL_DRIVER_VERSION,
00584         sizeof(attribute),attribute,&length);
00585       (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),"Driver: %s",
00586         attribute);
00587       clGetDeviceInfo(convolve_info->devices[0],CL_DEVICE_EXTENSIONS,
00588         sizeof(attribute),attribute,&length);
00589       (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),"Extensions: %s",
00590         attribute);
00591     }
00592   /*
00593     Create OpenCL command queue.
00594   */
00595   convolve_info->command_queue=clCreateCommandQueue(convolve_info->context,
00596     convolve_info->devices[0],0,&status);
00597   if ((convolve_info->command_queue == (cl_command_queue) NULL) ||
00598       (status != CL_SUCCESS))
00599     {
00600       convolve_info=DestroyConvolveInfo(convolve_info);
00601       return((ConvolveInfo *) NULL);
00602     }
00603   /*
00604     Build OpenCL program.
00605   */
00606   convolve_info->program=clCreateProgramWithSource(convolve_info->context,1,
00607     &source,lengths,&status);
00608   if ((convolve_info->program == (cl_program) NULL) || (status != CL_SUCCESS))
00609     {
00610       convolve_info=DestroyConvolveInfo(convolve_info);
00611       return((ConvolveInfo *) NULL);
00612     }
00613   (void) FormatLocaleString(options,MaxTextExtent,CLOptions,(float)
00614     QuantumRange,MagickEpsilon);
00615   status=clBuildProgram(convolve_info->program,1,convolve_info->devices,options,
00616     NULL,NULL);
00617   if ((convolve_info->program == (cl_program) NULL) || (status != CL_SUCCESS))
00618     {
00619       char
00620         *log;
00621 
00622       status=clGetProgramBuildInfo(convolve_info->program,
00623         convolve_info->devices[0],CL_PROGRAM_BUILD_LOG,0,NULL,&length);
00624       log=(char *) AcquireMagickMemory(length);
00625       if (log == (char *) NULL)
00626         {
00627           convolve_info=DestroyConvolveInfo(convolve_info);
00628           return((ConvolveInfo *) NULL);
00629         }
00630       status=clGetProgramBuildInfo(convolve_info->program,
00631         convolve_info->devices[0],CL_PROGRAM_BUILD_LOG,length,log,&length);
00632       (void) ThrowMagickException(exception,GetMagickModule(),DelegateWarning,
00633         "failed to build OpenCL program","`%s' (%s)",image->filename,log);
00634       log=DestroyString(log);
00635       convolve_info=DestroyConvolveInfo(convolve_info);
00636       return((ConvolveInfo *) NULL);
00637     }
00638   /*
00639     Get a kernel object.
00640   */
00641   convolve_info->kernel=clCreateKernel(convolve_info->program,name,&status);
00642   if ((convolve_info->kernel == (cl_kernel) NULL) || (status != CL_SUCCESS))
00643     {
00644       convolve_info=DestroyConvolveInfo(convolve_info);
00645       return((ConvolveInfo *) NULL);
00646     }
00647   return(convolve_info);
00648 }
00649 
00650 #endif
00651 
00652 MagickExport MagickBooleanType AccelerateConvolveImage(const Image *image,
00653   const KernelInfo *kernel,Image *convolve_image,ExceptionInfo *exception)
00654 {
00655   assert(image != (Image *) NULL);
00656   assert(image->signature == MagickSignature);
00657   if (image->debug != MagickFalse)
00658     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00659   assert(kernel != (KernelInfo *) NULL);
00660   assert(kernel->signature == MagickSignature);
00661   assert(convolve_image != (Image *) NULL);
00662   assert(convolve_image->signature == MagickSignature);
00663   assert(exception != (ExceptionInfo *) NULL);
00664   assert(exception->signature == MagickSignature);
00665   if ((image->storage_class != DirectClass) || 
00666       (image->colorspace == CMYKColorspace))
00667     return(MagickFalse);
00668   if ((GetImageVirtualPixelMethod(image) != UndefinedVirtualPixelMethod) &&
00669       (GetImageVirtualPixelMethod(image) != EdgeVirtualPixelMethod))
00670     return(MagickFalse);
00671   if (GetPixelChannels(image) != 4)
00672     return(MagickFalse);
00673 #if !defined(MAGICKCORE_OPENCL_SUPPORT)
00674   return(MagickFalse);
00675 #else
00676   {
00677     const void
00678       *pixels;
00679 
00680     float
00681       *filter;
00682 
00683     ConvolveInfo
00684       *convolve_info;
00685 
00686     MagickBooleanType
00687       status;
00688 
00689     MagickSizeType
00690       length;
00691 
00692     register ssize_t
00693       i;
00694 
00695     void
00696       *convolve_pixels;
00697 
00698     convolve_info=GetConvolveInfo(image,"Convolve",ConvolveKernel,exception);
00699     if (convolve_info == (ConvolveInfo *) NULL)
00700       return(MagickFalse);
00701     pixels=AcquirePixelCachePixels(image,&length,exception);
00702     if (pixels == (const void *) NULL)
00703       {
00704         convolve_info=DestroyConvolveInfo(convolve_info);
00705         (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
00706           "UnableToReadPixelCache","`%s'",image->filename);
00707         return(MagickFalse);
00708       }
00709     convolve_pixels=GetPixelCachePixels(convolve_image,&length,exception);
00710     if (convolve_pixels == (void *) NULL)
00711       {
00712         convolve_info=DestroyConvolveInfo(convolve_info);
00713         (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
00714           "UnableToReadPixelCache","`%s'",image->filename);
00715         return(MagickFalse);
00716       }
00717     filter=(float *) AcquireQuantumMemory(kernel->width,kernel->height*
00718       sizeof(*filter));
00719     if (filter == (float *) NULL)
00720       {
00721         DestroyConvolveBuffers(convolve_info);
00722         convolve_info=DestroyConvolveInfo(convolve_info);
00723         (void) ThrowMagickException(exception,GetMagickModule(),
00724           ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
00725         return(MagickFalse);
00726       }
00727     for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
00728       filter[i]=(float) kernel->values[i];
00729     status=BindConvolveParameters(convolve_info,image,pixels,filter,
00730       kernel->width,kernel->height,convolve_pixels);
00731     if (status == MagickFalse)
00732       {
00733         filter=(float *) RelinquishMagickMemory(filter);
00734         DestroyConvolveBuffers(convolve_info);
00735         convolve_info=DestroyConvolveInfo(convolve_info);
00736         return(MagickFalse);
00737       }
00738     status=EnqueueConvolveKernel(convolve_info,image,pixels,filter,
00739       kernel->width,kernel->height,convolve_pixels);
00740     filter=(float *) RelinquishMagickMemory(filter);
00741     if (status == MagickFalse)
00742       {
00743         DestroyConvolveBuffers(convolve_info);
00744         convolve_info=DestroyConvolveInfo(convolve_info);
00745         return(MagickFalse);
00746       }
00747     DestroyConvolveBuffers(convolve_info);
00748     convolve_info=DestroyConvolveInfo(convolve_info);
00749     return(MagickTrue);
00750   }
00751 #endif
00752 }