001/*
002 * JavaCL - Java API and utilities for OpenCL
003 * http://javacl.googlecode.com/
004 *
005 * Copyright (c) 2009-2013, Olivier Chafik (http://ochafik.com/)
006 * All rights reserved.
007 *
008 * Redistribution and use in source and binary forms, with or without
009 * modification, are permitted provided that the following conditions are met:
010 * 
011 *     * Redistributions of source code must retain the above copyright
012 *       notice, this list of conditions and the following disclaimer.
013 *     * Redistributions in binary form must reproduce the above copyright
014 *       notice, this list of conditions and the following disclaimer in the
015 *       documentation and/or other materials provided with the distribution.
016 *     * Neither the name of Olivier Chafik nor the
017 *       names of its contributors may be used to endorse or promote products
018 *       derived from this software without specific prior written permission.
019 * 
020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY
021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030 */
031        
032
033
034
035
036        
037
038        
039        
040
041
042
043        
044
045        
046        
047        
048
049        
050package com.nativelibs4java.opencl;
051import static com.nativelibs4java.opencl.CLException.*;
052import static com.nativelibs4java.opencl.JavaCL.CL;
053import static com.nativelibs4java.opencl.library.OpenCLLibrary.*;
054import static com.nativelibs4java.opencl.library.IOpenCLLibrary.*;
055
056import java.nio.Buffer;
057import java.nio.ByteBuffer;
058import java.nio.CharBuffer;
059import java.nio.DoubleBuffer;
060import java.nio.FloatBuffer;
061import java.nio.IntBuffer;
062import java.nio.LongBuffer;
063import java.nio.ShortBuffer;
064import java.util.HashMap;
065import java.util.Map;
066
067import com.nativelibs4java.opencl.library.IOpenCLLibrary.cl_device_id;
068import com.nativelibs4java.opencl.library.IOpenCLLibrary.cl_event;
069import com.nativelibs4java.opencl.library.IOpenCLLibrary.cl_kernel;
070import com.nativelibs4java.util.NIOUtils;
071
072import org.bridj.*;
073import static org.bridj.Pointer.*;
074
075/**
076 * OpenCL kernel.<br>
077 * A kernel is a function declared in a program. <br>
078 * A kernel is identified by the __kernel qualifier applied to any function in a program. <br>
079 * A kernel object encapsulates the specific __kernel function declared in a program and the argument values to be used when executing this __kernel function.<br>
080 * <br>
081 * Kernels can be queued for execution in a CLQueue (see enqueueTask and enqueueNDRange)
082 * See {@link CLProgram#createKernel(java.lang.String, java.lang.Object[])} and {@link CLProgram#createKernels()} 
083 * @author Olivier Chafik
084 */
085public class CLKernel extends CLAbstractEntity {
086
087    protected final CLProgram program;
088    protected String name;
089    
090        protected static CLInfoGetter infos = new CLInfoGetter() {
091                @Override
092                protected int getInfo(long entity, int infoTypeEnum, long size, Pointer out, Pointer<SizeT> sizeOut) {
093                        return CL.clGetKernelInfo(entity, infoTypeEnum, size, getPeer(out), getPeer(sizeOut));
094                }
095        };
096
097    private volatile CLInfoGetter kernelInfos;
098    protected synchronized CLInfoGetter getKernelInfos() {
099        if (kernelInfos == null)
100            kernelInfos = new CLInfoGetter() {
101
102                @Override
103                protected int getInfo(long entity, int infoTypeEnum, long size, Pointer out, Pointer<SizeT> sizeOut) {
104                    return CL.clGetKernelWorkGroupInfo(getEntity(), entity, infoTypeEnum, size, getPeer(out), getPeer(sizeOut));
105                }
106            };
107        return kernelInfos;
108    }
109
110    private final static int MAX_TMP_ITEMS = 16, MAX_TMP_ITEM_SIZE = 8;
111    
112    private final Pointer<?> localPointer = Pointer.allocateBytes(MAX_TMP_ITEM_SIZE * MAX_TMP_ITEMS).withoutValidityInformation();
113    
114    private final int contextAddressBits;
115    
116    CLKernel(CLProgram program, String name, long entity) {
117        super(entity);
118        this.program = program;
119        this.name = name;
120        this.contextAddressBits = getProgram().getContext().getAddressBits();
121    }
122        
123    public CLProgram getProgram() {
124        return program;
125    }
126
127    public String toString() {
128        return getFunctionName() + " {args: " + getNumArgs() + "}";//, workGroupSize = " + getWorkGroupSize() + ", localMemSize = " + getLocalMemSize() + "}";
129    }
130
131    /**
132     * Returns the preferred multiple of work- group size for launch. <br>
133     * This is a performance hint. <br>
134     * Specifying a work- group size that is not a multiple of the value returned by this query as the value of the local work size argument to clEnqueueNDRangeKernel will not fail to enqueue the kernel for execution unless the work-group size specified is larger than the device maximum.
135     * @since OpenCL 1.1
136     */
137    public Map<CLDevice, Long> getPreferredWorkGroupSizeMultiple() {
138                program.getContext().getPlatform().requireMinVersionValue("CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE", 1.1);
139        CLDevice[] devices = program.getDevices();
140        Map<CLDevice, Long> ret = new HashMap<CLDevice, Long>(devices.length);
141        for (CLDevice device : devices)
142            ret.put(device, getKernelInfos().getIntOrLong(device.getEntity(), CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE));
143        return ret;
144    }
145    
146    /**
147     * This provides a mechanism for the application to query the maximum work-group size that can be used to execute a kernel on a specific device given by device. <br>
148     * The OpenCL implementation uses the resource requirements of the kernel (register usage etc.) to determine what this work- group size should be.<br>
149     * See <a href="http://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/clGetKernelWorkGroupInfo.html">CL_KERNEL_WORK_GROUP_SIZE</a>
150     */
151    public Map<CLDevice, Long> getWorkGroupSize() {
152        CLDevice[] devices = program.getDevices();
153        Map<CLDevice, Long> ret = new HashMap<CLDevice, Long>(devices.length);
154        for (CLDevice device : devices)
155            ret.put(device, getKernelInfos().getIntOrLong(device.getEntity(), CL_KERNEL_WORK_GROUP_SIZE));
156        return ret;
157    }
158
159    /**
160     * Returns the work-group size specified by the __attribute__((reqd_work_gr oup_size(X, Y, Z))) qualifier.<br>
161     * Refer to section 6.7.2.<br>
162     * If the work-group size is not specified using the above attribute qualifier (0, 0, 0) is returned.<br>
163     * See <a href="http://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/clGetKernelWorkGroupInfo.html">CL_KERNEL_COMPILE_WORK_GROUP_SIZE</a>
164     * @return for each CLDevice, array of 3 longs
165     */
166    public Map<CLDevice, long[]> getCompileWorkGroupSize() {
167        CLDevice[] devices = program.getDevices();
168        Map<CLDevice, long[]> ret = new HashMap<CLDevice, long[]>(devices.length);
169        for (CLDevice device : devices)
170            ret.put(device, getKernelInfos().getNativeSizes(device.getEntity(), CL_KERNEL_COMPILE_WORK_GROUP_SIZE, 3));
171        return ret;
172    }
173    
174    /**
175     * Returns the amount of local memory in bytes being used by a kernel. <br>
176     * This includes local memory that may be needed by an implementation to execute the kernel, variables declared inside the kernel with the __local address qualifier and local memory to be allocated for arguments to the kernel declared as pointers with the __local address qualifier and whose size is specified with clSetKernelArg.<br>
177     * If the local memory size, for any pointer argument to the kernel declared with the __local address qualifier, is not specified, its size is assumed to be 0.<br>
178     * See <a href="http://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/clGetKernelWorkGroupInfo.html">CL_KERNEL_LOCAL_MEM_SIZE</a>
179     */
180    public Map<CLDevice, Long> getLocalMemSize() {
181        CLDevice[] devices = program.getDevices();
182        Map<CLDevice, Long> ret = new HashMap<CLDevice, Long>(devices.length);
183        for (CLDevice device : devices)
184            ret.put(device, getKernelInfos().getIntOrLong(device.getEntity(), CL_KERNEL_LOCAL_MEM_SIZE));
185        return ret;
186    }
187    
188    public void setArgs(Object... args) {
189                //assert getNumArgs() == args.length;
190        for (int i = 0, n = args.length; i < n; i++) {
191            setObjectArg(i, args[i]);
192        }
193    }
194
195    public static final Object NULL_POINTER_KERNEL_ARGUMENT = new Object() {};
196    
197    public void setObjectArg(int iArg, Object arg) {
198        boolean supported = true;
199        Class<?> cls;
200        if (arg instanceof CLAbstractEntity) {
201            setArg(iArg, (CLAbstractEntity) arg);
202        } else if (arg instanceof Number) {
203            if (arg instanceof Integer) {
204              setArg(iArg, (Integer) arg);
205            } else if (arg instanceof Long) {
206                setArg(iArg, (Long) arg);
207            } else if (arg instanceof Short) {
208                setArg(iArg, (Short) arg);
209            } else if (arg instanceof Byte) {
210                setArg(iArg, (Byte) arg);
211            } else if (arg instanceof Float) {
212                setArg(iArg, (Float) arg);
213            } else if (arg instanceof Double) {
214                setArg(iArg, (Double) arg);
215            } else {
216              supported = false;
217            } 
218        } else if (arg instanceof LocalSize) {
219                        setArg(iArg, (LocalSize)arg);
220                } else if (arg instanceof Boolean) {
221            setArg(iArg, (Boolean)arg);
222        } else if (arg instanceof SizeT) {
223            setArg(iArg, (SizeT)arg);
224        } else if (arg == NULL_POINTER_KERNEL_ARGUMENT) {
225            setArg(iArg, SizeT.ZERO);
226        } else if ((cls = arg.getClass()).isArray()) {
227                        if (arg instanceof int[]) {
228                                setArg(iArg, (int[])arg);
229                        } else if (arg instanceof long[]) {
230                                setArg(iArg, (long[])arg);
231                        } else if (arg instanceof short[]) {
232                                setArg(iArg, (short[])arg);
233                        } else if (arg instanceof double[]) {
234                                setArg(iArg, (double[])arg);
235                        } else if (arg instanceof float[]) {
236                                setArg(iArg, (float[])arg);
237                        } else if (arg instanceof byte[]) {
238                                setArg(iArg, (byte[])arg);
239                        } else if (arg instanceof boolean[]) {
240                                setArg(iArg, (boolean[])arg);
241                        } else {
242                                supported = false;
243                        }
244        } else if (arg instanceof Pointer) {
245            setArg(iArg, (Pointer)arg);
246                } else if (arg instanceof Buffer) {
247            setArg(iArg, pointerToBuffer((Buffer) arg));
248        } else {
249                        supported = false;
250        }
251        if (arg == null)
252            throw new IllegalArgumentException("Null arguments are not accepted. Please use CLKernel.NULL_POINTER_KERNEL_ARGUMENT instead.");
253
254        if (!supported) {
255                        throw new IllegalArgumentException("Cannot handle kernel arguments of type " + arg.getClass().getName() + ". Use CLKernel.get() and OpenCL4Java directly.");
256        }
257    }
258
259    /**
260  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
261     */
262    public void setArg(int i, LocalSize arg) {
263        setLocalArg(i, arg.size);
264    }
265    public void setLocalArg(int argIndex, long localArgByteLength) {
266        setKernelArg(argIndex, localArgByteLength, null);
267    }
268
269    private void setKernelArg(int i, long size, Pointer<?> ptr) {
270                if (size <= 0)
271                        throw new IllegalArgumentException("Kernel args must have a known byte size, given " + size + " instead.");
272                try {
273                error(CL.clSetKernelArg(getEntity(), i, size, getPeer(ptr)));
274                } catch (CLTypedException ex) {
275                        ex.setKernelArg(this, i);
276                        throw ex;
277                }
278    }
279    
280    /**
281  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
282     */
283    public void setArg(int i, Pointer<?> ptr) {
284                setKernelArg(i, ptr.getValidBytes(), ptr);
285    }
286    
287    /**
288  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
289     */
290    public void setArg(int i, float[] arg) {
291        setKernelArg(i, arg.length * 4, arg.length <= MAX_TMP_ITEMS ? localPointer.setFloats(arg) : pointerToFloats(arg));
292    }
293    /**
294  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
295     */
296    public void setArg(int i, int[] arg) {
297        setKernelArg(i, arg.length * 4, arg.length <= MAX_TMP_ITEMS ? localPointer.setInts(arg) : pointerToInts(arg));
298    }
299    /**
300  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
301     */
302    public void setArg(int i, double[] arg) {
303        setKernelArg(i, arg.length * 8, arg.length <= MAX_TMP_ITEMS ? localPointer.setDoubles(arg) : pointerToDoubles(arg));
304    }
305    /**
306  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
307     */
308    public void setArg(int i, long[] arg) {
309        setKernelArg(i, arg.length * 8, arg.length <= MAX_TMP_ITEMS ? localPointer.setLongs(arg) : pointerToLongs(arg));
310    }
311    /**
312  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
313     */
314    public void setArg(int i, short[] arg) {
315        setKernelArg(i, arg.length * 2, arg.length <= MAX_TMP_ITEMS ? localPointer.setShorts(arg) : pointerToShorts(arg));
316    }
317    /**
318  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
319     */
320    public void setArg(int i, byte[] arg) {
321        setKernelArg(i, arg.length, arg.length <= MAX_TMP_ITEMS ? localPointer.setBytes(arg) : pointerToBytes(arg));
322    }
323    /**
324  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
325     */
326    public void setArg(int i, boolean[] arg) {
327        setKernelArg(i, arg.length, arg.length <= MAX_TMP_ITEMS ? localPointer.setBooleans(arg) : pointerToBooleans(arg));
328    }
329    /**
330  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
331     */
332    public void setArg(int i, char[] arg) {
333        setKernelArg(i, arg.length * 2, arg.length <= MAX_TMP_ITEMS ? localPointer.setChars(arg) : pointerToChars(arg));
334    }
335    
336    /**
337  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
338     */
339    public void setArg(int i, SizeT arg) {
340        switch (contextAddressBits) {
341            case 32:
342                setKernelArg(i, 4, localPointer.setInt(arg.intValue()));
343                break;
344            case 64:
345                setKernelArg(i, 8, localPointer.setLong(arg.longValue()));
346                break;
347            default:
348                setKernelArg(i, SizeT.SIZE, localPointer.setSizeT(arg.longValue()));
349                break;
350        }
351    }
352
353    /**
354  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
355     */
356    public void setArg(int i, int arg) {
357        setKernelArg(i, 4, localPointer.setInt(arg));
358    }
359
360    /**
361  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
362     */
363    public void setArg(int i, long arg) {
364        setKernelArg(i, 8, localPointer.setLong(arg));
365    }
366
367    /**
368  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
369     */
370    public void setArg(int i, short arg) {
371        setKernelArg(i, 2, localPointer.setShort(arg));
372    }
373
374    /**
375  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
376     */
377    public void setArg(int i, byte arg) {
378        setKernelArg(i, 1, localPointer.setByte(arg));
379    }
380
381    /**
382  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
383     */
384    public void setArg(int i, boolean arg) {
385        setKernelArg(i, 1, localPointer.setByte(arg ? (byte)1 : (byte)0));
386    }
387
388    /**
389  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
390     */
391    public void setArg(int i, float arg) {
392        setKernelArg(i, 4, localPointer.setFloat(arg));
393    }
394
395    /**
396  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
397     */
398    public void setArg(int i, double arg) {
399        setKernelArg(i, 8, localPointer.setDouble(arg));
400    }
401
402    /**
403  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetKernelArg.html">clSetKernelArg</a>.<br>
404     */
405    public void setArg(int i, CLAbstractEntity arg) {
406        setKernelArg(i, Pointer.SIZE, localPointer.setSizeT(arg.getEntity()));
407    }
408
409    @Override
410    protected void clear() {
411        error(CL.clReleaseKernel(getEntity()));
412    }
413
414    private static final Pointer<SizeT> oneNL = pointerToSizeT(1);
415    /**
416  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueTask.html">clEnqueueTask</a>.<br>
417     * Enqueues a command to execute a kernel on a device. <br>
418     * The kernel is executed using a single work-item.
419     * @param queue
420         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
421     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
422     */
423    public CLEvent enqueueTask(CLQueue queue, CLEvent... eventsToWaitFor) {
424                        ReusablePointers ptrs = ReusablePointers.get();
425                int[] eventsInCount = ptrs.int1Array;
426        Pointer<cl_event> eventsIn = 
427                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
428                Pointer<cl_event> eventOut = 
429                eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
430                ? null 
431                : ptrs.event_out;
432        error(CL.clEnqueueTask(queue.getEntity(), getEntity(),   eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)  ));
433         return  CLEvent.createEventFromPointer(queue, eventOut) ;     }
434
435    /**
436  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueNDRangeKernel.html">clEnqueueNDRangeKernel</a>.<br>
437     * Enqueues a command to execute a kernel on a device (see {@link CLKernel#enqueueNDRange(CLQueue, int[], int[], int[], CLEvent[])})
438     * @param globalWorkSizes Each element describes the number of global work-items in a dimension that will execute the kernel function. The total number of global work-items is computed as globalWorkSizes[0] * ... * globalWorkSizes[globalWorkSizes.length - 1].
439     * @param localWorkSizes Each element describes the number of work-items that make up a work-group (also referred to as the size of the work-group) that will execute the kernel specified by kernel. The total number of work-items in a work-group is computed as localWorkSizes[0] * ... * localWorkSizes[localWorkSizes.length - 1]. The total number of work-items in the work-group must be less than or equal to the CL_DEVICE_MAX_WORK_GROUP_SIZE value specified in table 4.3 and the number of work- items specified in localWorkSizes[0], ... localWorkSizes[localWorkSizes.length - 1] must be less than or equal to the corresponding values specified by CLDevice.getMaxWorkItemSizes()[dimensionIndex].      The explicitly specified localWorkSize will be used to determine how to break the global work-items specified by global_work_size into appropriate work-group instances. If localWorkSize is specified, the values specified in globalWorkSize[dimensionIndex] must be evenly divisible by the corresponding values specified in localWorkSize[dimensionIndex]. This parameter can be left null, in which case the OpenCL implementation will choose good values.
440     * @param queue This kernel will be queued for execution on the device associated with that queue.
441         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
442     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
443     */
444    public CLEvent enqueueNDRange(CLQueue queue /*, int[] globalOffsets*/, int[] globalWorkSizes, int[] localWorkSizes, CLEvent... eventsToWaitFor) {
445        return enqueueNDRange(queue, null, globalWorkSizes, localWorkSizes, eventsToWaitFor);
446    }
447    
448    /**
449  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueNDRangeKernel.html">clEnqueueNDRangeKernel</a>.<br>
450     * Enqueues a command to execute a kernel on a device, using local work sizes chosen by the OpenCL implementation.
451     * See {@link CLKernel#enqueueNDRange(CLQueue, int[], int[], int[], CLEvent[])}
452     * @param globalWorkSizes Each element describes the number of global work-items in a dimension that will execute the kernel function. The total number of global work-items is computed as globalWorkSizes[0] * ... * globalWorkSizes[globalWorkSizes.length - 1].
453     * @param queue This kernel will be queued for execution on the device associated with that queue.
454         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
455     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
456     */
457    public CLEvent enqueueNDRange(CLQueue queue /*, int[] globalOffsets*/, int[] globalWorkSizes, CLEvent... eventsToWaitFor) {
458        return enqueueNDRange(queue, null, globalWorkSizes, null, eventsToWaitFor);
459    }
460    
461    /**
462  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueNDRangeKernel.html">clEnqueueNDRangeKernel</a>.<br>
463     * Enqueues a command to execute a kernel on a device.
464     * @param globalOffsets Must be null in OpenCL 1.0. Each element describes the offset used to calculate the global ID of a work-item. If globalOffsets is null, the global IDs start at offset (0, 0, ... 0).
465     * @param globalWorkSizes Each element describes the number of global work-items in a dimension that will execute the kernel function. The total number of global work-items is computed as globalWorkSizes[0] * ... * globalWorkSizes[globalWorkSizes.length - 1].
466     * @param localWorkSizes Each element describes the number of work-items that make up a work-group (also referred to as the size of the work-group) that will execute the kernel specified by kernel. The total number of work-items in a work-group is computed as localWorkSizes[0] * ... * localWorkSizes[localWorkSizes.length - 1]. The total number of work-items in the work-group must be less than or equal to the CL_DEVICE_MAX_WORK_GROUP_SIZE value specified in table 4.3 and the number of work- items specified in localWorkSizes[0], ... localWorkSizes[localWorkSizes.length - 1] must be less than or equal to the corresponding values specified by CLDevice.getMaxWorkItemSizes()[dimensionIndex].      The explicitly specified localWorkSize will be used to determine how to break the global work-items specified by global_work_size into appropriate work-group instances. If localWorkSize is specified, the values specified in globalWorkSize[dimensionIndex] must be evenly divisible by the corresponding values specified in localWorkSize[dimensionIndex]. This parameter can be left null, in which case the OpenCL implementation will choose good values.
467     * @param queue This kernel will be queued for execution on the device associated with that queue.
468         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
469     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
470     */
471    public CLEvent enqueueNDRange(CLQueue queue, long[] globalOffsets, long[] globalWorkSizes, long[] localWorkSizes, CLEvent... eventsToWaitFor) {
472        int nDims = globalWorkSizes.length;
473        if (localWorkSizes != null && localWorkSizes.length != nDims) {
474            throw new IllegalArgumentException("Global and local sizes must have same dimensions, given " + globalWorkSizes.length + " vs. " + localWorkSizes.length);
475        }
476        
477                        ReusablePointers ptrs = ReusablePointers.get();
478                int[] eventsInCount = ptrs.int1Array;
479        Pointer<cl_event> eventsIn = 
480                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
481                Pointer<cl_event> eventOut = 
482                eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
483                ? null 
484                : ptrs.event_out;
485        error(CL.clEnqueueNDRangeKernel(
486            queue.getEntity(),
487            getEntity(),
488            nDims,
489            getPeer(ptrs.sizeT3_1.pointerToSizeTs(globalOffsets)),
490            getPeer(ptrs.sizeT3_2.pointerToSizeTs(globalWorkSizes)),
491            getPeer(ptrs.sizeT3_3.pointerToSizeTs(localWorkSizes)),
492              eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)          ));
493         return  CLEvent.createEventFromPointer(queue, eventOut) ;     }
494    
495    /**
496     * @deprecated Use {@link CLKernel#enqueueNDRange(CLQueue, long[], long[], long[], CLEvent[])} instead.
497     */
498    @Deprecated
499    public CLEvent enqueueNDRange(CLQueue queue, int[] globalOffsets, int[] globalWorkSizes, int[] localWorkSizes, CLEvent... eventsToWaitFor) {
500        int nDims = globalWorkSizes.length;
501        if (localWorkSizes != null && localWorkSizes.length != nDims) {
502            throw new IllegalArgumentException("Global and local sizes must have same dimensions, given " + globalWorkSizes.length + " vs. " + localWorkSizes.length);
503        }
504                        ReusablePointers ptrs = ReusablePointers.get();
505                int[] eventsInCount = ptrs.int1Array;
506        Pointer<cl_event> eventsIn = 
507                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
508                Pointer<cl_event> eventOut = 
509                eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
510                ? null 
511                : ptrs.event_out;
512        error(CL.clEnqueueNDRangeKernel(
513            queue.getEntity(),
514            getEntity(),
515            nDims,
516            getPeer(ptrs.sizeT3_1.pointerToSizeTs(globalOffsets)),
517            getPeer(ptrs.sizeT3_2.pointerToSizeTs(globalWorkSizes)),
518            getPeer(ptrs.sizeT3_3.pointerToSizeTs(localWorkSizes)),
519              eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)  ));
520         return  CLEvent.createEventFromPointer(queue, eventOut) ;     }
521        
522        /**
523         * Return the number of arguments to kernel.
524         */
525    @InfoName("CL_KERNEL_NUM_ARGS")
526    public int getNumArgs() {
527                int numArgs = infos.getInt(getEntity(), CL_KERNEL_NUM_ARGS);
528                //System.out.println("numArgs = " + numArgs);
529        return numArgs;
530    }
531
532    /**
533     * Return the kernel function name.
534     */
535    @InfoName("CL_KERNEL_FUNCTION_NAME")
536    public String getFunctionName() {
537        if (name == null)
538            name = infos.getString(getEntity(), CL_KERNEL_FUNCTION_NAME);
539        return name;
540    }
541}