package com.mbien.opencl; import java.nio.Buffer; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import static com.mbien.opencl.CLException.*; /** * The command-queue can be used to queue a set of operations in order. Having multiple * command-queues allows applications to queue multiple independent commands without * requiring synchronization. Note that this should work as long as these objects are * not being shared. * Sharing of objects across multiple command-queues will require the application to * perform appropriate synchronization. * @author Michael Bien */ public class CLCommandQueue implements CLResource { public final long ID; private final CLContext context; private final CLDevice device; private final CL cl; CLCommandQueue(CLContext context, CLDevice device, long properties) { this.context = context; this.cl = context.cl; this.device = device; int[] status = new int[1]; this.ID = cl.clCreateCommandQueue(context.ID, device.ID, properties, status, 0); if(status[0] != CL.CL_SUCCESS) throw new CLException(status[0], "can not create command queue on "+device); } public CLCommandQueue putWriteBuffer(CLBuffer writeBuffer, boolean blockingWrite) { int ret = cl.clEnqueueWriteBuffer( ID, writeBuffer.ID, blockingWrite ? CL.CL_TRUE : CL.CL_FALSE, 0, writeBuffer.getSizeInBytes(), writeBuffer.buffer, // 0, null, null); //TODO solve NPE in gluegen when PointerBuffer == null (fast dircet memory path) 0, null, 0, null, 0); //TODO events if(ret != CL.CL_SUCCESS) throw new CLException(ret, "can not enqueue WriteBuffer: " + writeBuffer); return this; } public CLCommandQueue putReadBuffer(CLBuffer readBuffer, boolean blockingRead) { int ret = cl.clEnqueueReadBuffer( ID, readBuffer.ID, blockingRead ? CL.CL_TRUE : CL.CL_FALSE, 0, readBuffer.getSizeInBytes(), readBuffer.buffer, // 0, null, null); //TODO solve NPE in gluegen when PointerBuffer == null (fast dircet memory path) 0, null, 0, null, 0); //TODO events if(ret != CL.CL_SUCCESS) throw new CLException(ret, "can not enqueue ReadBuffer: " + readBuffer); return this; } public CLCommandQueue putReadBuffer(CLBuffer readBuffer, Buffer buffer, boolean blockingRead) { int ret = cl.clEnqueueReadBuffer( ID, readBuffer.ID, blockingRead ? CL.CL_TRUE : CL.CL_FALSE, 0, readBuffer.getSizeInBytes(), buffer, // 0, null, null); //TODO solve NPE in gluegen when PointerBuffer == null (fast dircet memory path) 0, null, 0, null, 0); //TODO events if(ret != CL.CL_SUCCESS) throw new CLException(ret, "can not enqueue ReadBuffer: " + readBuffer); return this; } public CLCommandQueue putBarrier() { int ret = cl.clEnqueueBarrier(ID); checkForError(ret, "can not enqueue Barrier"); return this; } public CLCommandQueue putCopyBuffer(CLBuffer src, CLBuffer dest, long bytesToCopy) { int ret = cl.clEnqueueCopyBuffer( ID, src.ID, dest.ID, src.buffer.position(), dest.buffer.position(), bytesToCopy, // 0, null, null); //TODO solve NPE in gluegen when PointerBuffer == null 0, null, 0, null, 0); //TODO events checkForError(ret, "can not copy Buffer"); return this; } //TODO implement remaining methods /* public CLCommandQueue putCopyImage() { return this; } public CLCommandQueue putCopyBufferToImage() { return this; } public CLCommandQueue putCopyImageToBuffer() { return this; } public CLCommandQueue putMarker() { return this; } public CLCommandQueue putWriteImage() { return this; } public CLCommandQueue putReadImage() { return this; } public CLCommandQueue putTask() { return this; } public CLBuffer putMapBuffer() { return null; } public CLCommandQueue putMapImage() { return this; } public CLCommandQueue putUnmapMemObject() { return this; } public CLCommandQueue putWaitForEvents() { return this; } */ public CLCommandQueue put1DRangeKernel(CLKernel kernel, long globalWorkOffset, long globalWorkSize, long localWorkSize) { return this.putNDRangeKernel( kernel, 1, globalWorkOffset==0 ? null : new long[] {globalWorkOffset}, globalWorkSize ==0 ? null : new long[] {globalWorkSize }, localWorkSize ==0 ? null : new long[] {localWorkSize } ); } public CLCommandQueue put2DRangeKernel(CLKernel kernel, long globalWorkOffsetX, long globalWorkOffsetY, long globalWorkSizeX, long globalWorkSizeY, long localWorkSizeX, long localWorkSizeY) { return this.putNDRangeKernel( kernel, 2, globalWorkOffsetX==0 && globalWorkOffsetY==0 ? null : new long[] {globalWorkOffsetX, globalWorkOffsetY}, globalWorkSizeX ==0 && globalWorkSizeY ==0 ? null : new long[] {globalWorkSizeX, globalWorkSizeY }, localWorkSizeX ==0 && localWorkSizeY ==0 ? null : new long[] {localWorkSizeX, localWorkSizeY } ); } public CLCommandQueue putNDRangeKernel(CLKernel kernel, int workDimension, long[] globalWorkOffset, long[] globalWorkSize, long[] localWorkSize) { int ret = cl.clEnqueueNDRangeKernel( ID, kernel.ID, workDimension, globalWorkOffset, 0, globalWorkSize, 0, localWorkSize, 0, 0, null, 0, null, 0 ); if(ret != CL.CL_SUCCESS) throw new CLException(ret, "can not enqueue NDRangeKernel: " + kernel); return this; } public CLCommandQueue putAcquireGLObject(long glObject) { CLGLI xl = (CLGLI) cl; int ret = xl.clEnqueueAcquireGLObjects(ID, 1, new long[] {glObject}, 0, 0, null, 0, null, 0); if(ret != CL.CL_SUCCESS) throw new CLException(ret, "can not aquire GLObject: " + glObject); return this; } public CLCommandQueue putReleaseGLObject(long glObject) { CLGLI xl = (CLGLI) cl; int ret = xl.clEnqueueReleaseGLObjects(ID, 1, new long[] {glObject}, 0, 0, null, 0, null, 0); if(ret != CL.CL_SUCCESS) throw new CLException(ret, "can not release GLObject: " + glObject); return this; } public CLCommandQueue finish() { int ret = cl.clFinish(ID); checkForError(ret, "can not finish command queue"); return this; } public void release() { int ret = cl.clReleaseCommandQueue(ID); context.onCommandQueueReleased(device, this); checkForError(ret, "can not release command queue"); } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final CLCommandQueue other = (CLCommandQueue) obj; if (this.ID != other.ID) { return false; } if (this.context != other.context && (this.context == null || !this.context.equals(other.context))) { return false; } if (this.device != other.device && (this.device == null || !this.device.equals(other.device))) { return false; } return true; } @Override public int hashCode() { int hash = 3; hash = 89 * hash + (int) (this.ID ^ (this.ID >>> 32)); hash = 89 * hash + (this.context != null ? this.context.hashCode() : 0); hash = 89 * hash + (this.device != null ? this.device.hashCode() : 0); return hash; } /** * Enumeration for the command-queue settings. */ public enum Mode { /** * CL_DEVICE_TYPE_CPU */ OUT_OF_ORDER_EXEC_MODE(CL.CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE), /** * CL_DEVICE_TYPE_GPU */ PROFILING_MODE(CL.CL_QUEUE_PROFILING_ENABLE); /** * Value of wrapped OpenCL device type. */ public final int CL_QUEUE_MODE; private Mode(int CL_VALUE) { this.CL_QUEUE_MODE = CL_VALUE; } public static Mode valueOf(int queueMode) { switch(queueMode) { case(CL.CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE): return OUT_OF_ORDER_EXEC_MODE; case(CL.CL_QUEUE_PROFILING_ENABLE): return PROFILING_MODE; } return null; } public static EnumSet valuesOf(int bitfield) { List matching = new ArrayList(); Mode[] values = Mode.values(); for (Mode value : values) { if((value.CL_QUEUE_MODE & bitfield) != 0) matching.add(value); } if(matching.isEmpty()) return EnumSet.noneOf(Mode.class); else return EnumSet.copyOf(matching); } } }