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.error; 052import static com.nativelibs4java.opencl.JavaCL.CL; 053import static com.nativelibs4java.opencl.library.IOpenCLLibrary.CL_FALSE; 054import static com.nativelibs4java.opencl.library.IOpenCLLibrary.CL_QUEUE_PROPERTIES; 055import static com.nativelibs4java.opencl.library.IOpenCLLibrary.CL_TRUE; 056 057import java.util.EnumSet; 058 059import com.nativelibs4java.opencl.library.IOpenCLLibrary.cl_command_queue; 060import com.nativelibs4java.opencl.library.IOpenCLLibrary.cl_event; 061import com.nativelibs4java.opencl.library.IOpenCLLibrary.cl_mem; 062import org.bridj.*; 063import static org.bridj.Pointer.*; 064 065/** 066 * OpenCL command queue.<br> 067 * OpenCL objects such as memory, program and kernel objects are created using a context. <br> 068 * Operations on these objects are performed using a command-queue. <br> 069 * The command-queue can be used to queue a set of operations (referred to as commands) in order. <br> 070 * Having multiple command-queues allows applications to queue multiple independent commands without requiring synchronization. <br> 071 * Note that this should work as long as these objects are not being shared. <br> 072 * Sharing of objects across multiple command-queues will require the application to perform appropriate synchronization.<br> 073 * <br> 074 * A queue is bound to a single device. 075 * see {@link CLDevice#createQueue(com.nativelibs4java.opencl.CLContext, com.nativelibs4java.opencl.CLDevice.QueueProperties[]) } 076 * see {@link CLDevice#createOutOfOrderQueue(com.nativelibs4java.opencl.CLContext) } 077 * see {@link CLDevice#createProfilingQueue(com.nativelibs4java.opencl.CLContext) } 078 * see {@link CLContext#createDefaultQueue(com.nativelibs4java.opencl.CLDevice.QueueProperties[]) } 079 * see {@link CLContext#createDefaultOutOfOrderQueue() } 080 * see {@link CLContext#createDefaultProfilingQueue() } 081 * @author Olivier Chafik 082 * 083 */ 084public class CLQueue extends CLAbstractEntity { 085 086 protected static CLInfoGetter infos = new CLInfoGetter() { 087 @Override 088 protected int getInfo(long entity, int infoTypeEnum, long size, Pointer out, Pointer<SizeT> sizeOut) { 089 return CL.clGetCommandQueueInfo(entity, infoTypeEnum, size, getPeer(out), getPeer(sizeOut)); 090 } 091 }; 092 093 final CLContext context; 094 final CLDevice device; 095 096 CLQueue(CLContext context, long entity, CLDevice device) { 097 super(entity); 098 this.context = context; 099 this.device = device; 100 } 101 102 public CLContext getContext() { 103 return context; 104 } 105 public CLDevice getDevice() { 106 return device; 107 } 108 109 volatile Boolean outOfOrder; 110 public synchronized boolean isOutOfOrder() { 111 if (outOfOrder == null) 112 outOfOrder = getProperties().contains(CLDevice.QueueProperties.OutOfOrderExecModeEnable); 113 return outOfOrder; 114 } 115 116 @InfoName("CL_QUEUE_PROPERTIES") 117 public EnumSet<CLDevice.QueueProperties> getProperties() { 118 return CLDevice.QueueProperties.getEnumSet(infos.getIntOrLong(getEntity(), CL_QUEUE_PROPERTIES)); 119 } 120 121 @SuppressWarnings("deprecation") 122 public void setProperty(CLDevice.QueueProperties property, boolean enabled) { 123 context.getPlatform().requireMinVersionValue("clSetCommandQueueProperty", 1.0, 1.1); 124 error(CL.clSetCommandQueueProperty(getEntity(), property.value(), enabled ? CL_TRUE : CL_FALSE, 0)); 125 } 126 127 128 @Override 129 protected void clear() { 130 error(CL.clReleaseCommandQueue(getEntity())); 131 } 132 133 /** 134 * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clFinish.html">clFinish</a>.<br> 135 * Blocks until all previously queued OpenCL commands in this queue are issued to the associated device and have completed. <br> 136 * finish() does not return until all queued commands in this queue have been processed and completed. <br> 137 * finish() is also a synchronization point. 138 */ 139 public void finish() { 140 error(CL.clFinish(getEntity())); 141 } 142 143 /** 144 * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clFlush.html">clFlush</a>.<br> 145 * Issues all previously queued OpenCL commands in this queue to the device associated with this queue. <br> 146 * flush() only guarantees that all queued commands in this queue get issued to the appropriate device. <br> 147 * There is no guarantee that they will be complete after flush() returns. 148 */ 149 public void flush() { 150 error(CL.clFlush(getEntity())); 151 } 152 153 /** 154 * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueWaitForEvents.html">clEnqueueWaitForEvents</a>.<br> 155 * Enqueues a wait for a specific event or a list of events to complete before any future commands queued in the this queue are executed. 156 */ 157 public void enqueueWaitForEvents(CLEvent... eventsToWaitFor) { 158 context.getPlatform().requireMinVersionValue("clEnqueueWaitForEvents", 1.1, 1.2); 159 ReusablePointers ptrs = ReusablePointers.get(); 160 int[] eventsInCount = ptrs.int1Array; 161 Pointer<cl_event> eventsIn = 162 CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in); 163 if (eventsIn == null) 164 return; 165 error(CL.clEnqueueWaitForEvents(getEntity(), eventsInCount[0], getPeer(eventsIn) )); 166 } 167 168 169 /** 170 * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueMigrateMemObjects.html">clEnqueueMigrateMemObjects</a>.<br> 171 * Enqueues a command to indicate which device a set of memory objects should be associated with. 172 */ 173 public CLEvent enqueueMigrateMemObjects(CLMem[] memObjects, EnumSet<CLMem.Migration> flags, CLEvent... eventsToWaitFor) { 174 context.getPlatform().requireMinVersionValue("clEnqueueMigrateMemObjects", 1.2); 175 ReusablePointers ptrs = ReusablePointers.get(); 176 int[] eventsInCount = ptrs.int1Array; 177 Pointer<cl_event> eventsIn = 178 CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in); 179 Pointer<cl_event> eventOut = 180 eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 181 ? null 182 : ptrs.event_out; 183 int[] n = ptrs.int1Array; 184 Pointer<SizeT> pMems = pointerToEntities(memObjects, n); 185 error(CL.clEnqueueMigrateMemObjects( 186 getEntity(), 187 n[0], 188 getPeer(pMems), 189 CLMem.Migration.getValue(flags), 190 eventsInCount[0], getPeer(eventsIn) , getPeer(eventOut) )); 191 return CLEvent.createEventFromPointer(this, eventOut) ; } 192 193 // 194 public interface NativeKernel { 195 void execute(Pointer[] bufferPointers); 196 } 197 198 private static Pointer<SizeT> pointerToEntities(CLAbstractEntity[] entities, int[] n) { 199 int nn = 0; 200 Pointer<SizeT> pEntities = allocateSizeTs(entities.length); 201 for (CLAbstractEntity entity : entities) { 202 if (entity != null) { 203 pEntities.setSizeTAtIndex(nn++, entity.getEntity()); 204 } 205 } 206 n[0] = nn; 207 return pEntities; 208 } 209 /** 210 * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueNativeKernel.html">clEnqueueNativeKernel</a>.<br> 211 * Enqueues a command to execute a Java callback with direct access to buffer memory. 212 */ 213 /* 214 public CLEvent enqueueNativeKernel(NativeKernel kernel, CLMem[] buffers, CLEvent... eventsToWaitFor) { 215 // TODO check 1.1 or 1.2? 216 context.getPlatform().requireMinVersionValue("clEnqueueNativeKernel", 1.2); 217 ReusablePointers ptrs = ReusablePointers.get(); 218 int[] eventsInCount = ptrs.int1Array; 219 Pointer<cl_event> eventsIn = 220 CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in); 221 Pointer<cl_event> eventOut = 222 eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 223 ? null 224 : ptrs.event_out; 225 int[] n = ptrs.int1Array; 226 Pointer<SizeT> pMems = pointerToEntities(buffers, n); 227 error(CL.clEnqueueNativeKernel( 228 getEntity(), 229 n[0], 230 getPeer(pMems), 231 CLMem.Migration.getValue(flags), 232 eventsInCount[0], getPeer(eventsIn) , getPeer(eventOut) )); 233 return CLEvent.createEventFromPointer(this, eventOut) ; } 234 */ 235 236 /** 237 * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueBarrierWithWaitList.html">clEnqueueBarrierWithWaitList</a>.<br> 238 * Enqueue a barrier operation.<br> 239 * The enqueueBarrier() command ensures that all queued commands in command_queue have finished execution before the next batch of commands can begin execution. <br> 240 * enqueueBarrier() is a synchronization point. 241 * @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. 242 * @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}. 243 */ 244 public CLEvent enqueueBarrier(CLEvent... eventsToWaitFor) { 245 if (context.getPlatform().getVersionValue() >= 1.2 || 246 eventsToWaitFor != null && eventsToWaitFor.length > 0) 247 { 248 context.getPlatform().requireMinVersionValue("clEnqueueBarrierWithWaitList", 1.2); 249 ReusablePointers ptrs = ReusablePointers.get(); 250 int[] eventsInCount = ptrs.int1Array; 251 Pointer<cl_event> eventsIn = 252 CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in); 253 Pointer<cl_event> eventOut = 254 eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 255 ? null 256 : ptrs.event_out; 257 error(CL.clEnqueueBarrierWithWaitList( 258 getEntity(), 259 eventsInCount[0], getPeer(eventsIn) , getPeer(eventOut) )); 260 return CLEvent.createEventFromPointer(this, eventOut) ; } else { 261 context.getPlatform().requireMinVersionValue("clEnqueueBarrier", 1.1, 1.2); 262 error(CL.clEnqueueBarrier(getEntity())); 263 return null; 264 } 265 } 266 267 /** 268 * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueMarkerWithWaitList.html">clEnqueueMarkerWithWaitList</a>.<br> 269 * Enqueue a marker command to command_queue. <br> 270 * The marker command returns an event which can be used by to queue a wait on this marker event i.e. wait for all commands queued before the marker command to complete. 271 * @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. 272 * @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}. 273 */ 274 @Deprecated 275 public CLEvent enqueueMarker(CLEvent... eventsToWaitFor) { 276 if (context.getPlatform().getVersionValue() >= 1.2 || 277 eventsToWaitFor != null && eventsToWaitFor.length > 0) 278 { 279 context.getPlatform().requireMinVersionValue("clEnqueueMarkerWithWaitList", 1.2); 280 ReusablePointers ptrs = ReusablePointers.get(); 281 int[] eventsInCount = ptrs.int1Array; 282 Pointer<cl_event> eventsIn = 283 CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in); 284 Pointer<cl_event> eventOut = 285 eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 286 ? null 287 : ptrs.event_out; 288 error(CL.clEnqueueMarkerWithWaitList( 289 getEntity(), 290 eventsInCount[0], getPeer(eventsIn) , getPeer(eventOut) )); 291 return CLEvent.createEventFromPointer(this, eventOut) ; } else { 292 context.getPlatform().requireMinVersionValue("clEnqueueMarker", 1.1, 1.2); 293 ReusablePointers ptrs = ReusablePointers.get(); 294 Pointer<cl_event> eventOut = ptrs.event_out; 295 error(CL.clEnqueueMarker(getEntity(), getPeer(eventOut))); 296 return CLEvent.createEventFromPointer(this, eventOut) ; } 297 } 298 299 /** 300 * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueAcquireGLObjects.html">clEnqueueAcquireGLObjects</a>.<br> 301 * Used to acquire OpenCL memory objects that have been created from OpenGL objects. <br> 302 * These objects need to be acquired before they can be used by any OpenCL commands queued to a command-queue. <br> 303 * The OpenGL objects are acquired by the OpenCL context associated with this queue and can therefore be used by all command-queues associated with the OpenCL context. 304 * @param objects CL memory objects that correspond to GL objects. 305 * @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. 306 * @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}. 307 */ 308 public CLEvent enqueueAcquireGLObjects(CLMem[] objects, CLEvent... eventsToWaitFor) { 309 ReusablePointers ptrs = ReusablePointers.get(); 310 int[] eventsInCount = ptrs.int1Array; 311 Pointer<cl_event> eventsIn = 312 CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in); 313 Pointer<cl_event> eventOut = 314 eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 315 ? null 316 : ptrs.event_out; 317 Pointer<SizeT> mems = allocateSizeTs(objects.length); 318 for (int i = 0; i < objects.length; i++) { 319 mems.setSizeTAtIndex(i, objects[i].getEntity()); 320 } 321 error(CL.clEnqueueAcquireGLObjects( 322 getEntity(), 323 objects.length, 324 getPeer(mems), 325 eventsInCount[0], getPeer(eventsIn) , getPeer(eventOut) )); 326 return CLEvent.createEventFromPointer(this, eventOut) ; } 327 328 /** 329 * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueReleaseGLObjects.html">clEnqueueReleaseGLObjects</a>.<br> 330 * Used to release OpenCL memory objects that have been created from OpenGL objects. <br> 331 * These objects need to be released before they can be used by OpenGL. <br> 332 * The OpenGL objects are released by the OpenCL context associated with this queue. 333 * @param objects CL memory objects that correpond to GL objects. 334 * @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. 335 * @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}. 336 */ 337 public CLEvent enqueueReleaseGLObjects(CLMem[] objects, CLEvent... eventsToWaitFor) { 338 ReusablePointers ptrs = ReusablePointers.get(); 339 int[] eventsInCount = ptrs.int1Array; 340 Pointer<cl_event> eventsIn = 341 CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in); 342 Pointer<cl_event> eventOut = 343 eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 344 ? null 345 : ptrs.event_out; 346 Pointer<?> mems = getEntities(objects, (Pointer)allocateSizeTs(objects.length)); 347 error(CL.clEnqueueReleaseGLObjects( 348 getEntity(), 349 objects.length, 350 getPeer(mems), 351 eventsInCount[0], getPeer(eventsIn) , getPeer(eventOut) )); 352 return CLEvent.createEventFromPointer(this, eventOut) ; } 353}