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}