diff options
Diffstat (limited to 'src/com/mbien')
-rw-r--r-- | src/com/mbien/opencl/CLBuffer.java | 127 | ||||
-rw-r--r-- | src/com/mbien/opencl/CLCommandQueue.java | 38 | ||||
-rw-r--r-- | src/com/mbien/opencl/CLContext.java | 98 | ||||
-rw-r--r-- | src/com/mbien/opencl/CLDevice.java | 150 | ||||
-rw-r--r-- | src/com/mbien/opencl/CLKernel.java | 3 | ||||
-rw-r--r-- | src/com/mbien/opencl/CLProgram.java | 257 |
6 files changed, 408 insertions, 265 deletions
diff --git a/src/com/mbien/opencl/CLBuffer.java b/src/com/mbien/opencl/CLBuffer.java index 185389c3..7c195ba7 100644 --- a/src/com/mbien/opencl/CLBuffer.java +++ b/src/com/mbien/opencl/CLBuffer.java @@ -9,7 +9,65 @@ import static com.mbien.opencl.CLException.*; */ public class CLBuffer { - public enum MEM { + public final ByteBuffer buffer; + public final long ID; + + private final CLContext context; + private final CL cl; + + CLBuffer(CLContext context, ByteBuffer directBuffer, int flags) { + + if(!directBuffer.isDirect()) + throw new IllegalArgumentException("buffer is not a direct buffer"); + + this.buffer = directBuffer; + this.context = context; + this.cl = context.cl; + + int[] intArray = new int[1]; + + this.ID = cl.clCreateBuffer(context.ID, flags, directBuffer.capacity(), null, intArray, 0); + + checkForError(intArray[0], "can not create cl buffer"); + + } + + public void release() { + int ret = cl.clReleaseMemObject(ID); + context.onBufferReleased(this); + checkForError(ret, "can not release mem object"); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final CLBuffer other = (CLBuffer) obj; + if (this.buffer != other.buffer && (this.buffer == null || !this.buffer.equals(other.buffer))) { + return false; + } + if (this.context.ID != other.context.ID) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 3; + hash = 29 * hash + (this.buffer != null ? this.buffer.hashCode() : 0); + hash = 29 * hash + (int) (this.context.ID ^ (this.context.ID >>> 32)); + return hash; + } + + /** + * Memory settings for configuring CLBuffers. + */ + public enum Mem { /** * This flag specifies that the memory object will be read and @@ -56,11 +114,11 @@ public class CLBuffer { */ public final int CL_FLAG; - private MEM(int CL_TYPE) { - this.CL_FLAG = CL_TYPE; + private Mem(int CL_FLAG) { + this.CL_FLAG = CL_FLAG; } - public static MEM valueOf(int bufferFlag) { + public static Mem valueOf(int bufferFlag) { switch(bufferFlag) { case(CL.CL_MEM_READ_WRITE): return READ_WRITE; @@ -76,7 +134,7 @@ public class CLBuffer { return null; } - static int flagsToInt(MEM[] flags) { + static int flagsToInt(Mem[] flags) { int clFlags = 0; if(flags != null) { for (int i = 0; i < flags.length; i++) { @@ -90,63 +148,4 @@ public class CLBuffer { } - - public final ByteBuffer buffer; - public final long ID; - - private final CLContext context; - private final CL cl; - - CLBuffer(CLContext context, ByteBuffer directBuffer, int flags) { - - if(!directBuffer.isDirect()) - throw new IllegalArgumentException("buffer is not a direct buffer"); - - this.buffer = directBuffer; - this.context = context; - this.cl = context.cl; - - int[] intArray = new int[1]; - - this.ID = cl.clCreateBuffer(context.ID, flags, directBuffer.capacity(), null, intArray, 0); - - checkForError(intArray[0], "can not create cl buffer"); - - } - - public void release() { - int ret = cl.clReleaseMemObject(ID); - context.onBufferReleased(this); - checkForError(ret, "can not release mem object"); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final CLBuffer other = (CLBuffer) obj; - if (this.buffer != other.buffer && (this.buffer == null || !this.buffer.equals(other.buffer))) { - return false; - } - if (this.context.ID != other.context.ID) { - return false; - } - return true; - } - - @Override - public int hashCode() { - int hash = 3; - hash = 29 * hash + (this.buffer != null ? this.buffer.hashCode() : 0); - hash = 29 * hash + (int) (this.context.ID ^ (this.context.ID >>> 32)); - return hash; - } - - - - } diff --git a/src/com/mbien/opencl/CLCommandQueue.java b/src/com/mbien/opencl/CLCommandQueue.java index 5abc5cd5..00e1d6b0 100644 --- a/src/com/mbien/opencl/CLCommandQueue.java +++ b/src/com/mbien/opencl/CLCommandQueue.java @@ -3,7 +3,12 @@ package com.mbien.opencl; 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.<b/> + * Sharing of objects across multiple command-queues will require the application to + * perform appropriate synchronization. * @author Michael Bien */ public class CLCommandQueue { @@ -190,5 +195,36 @@ public class CLCommandQueue { 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; + } + } } diff --git a/src/com/mbien/opencl/CLContext.java b/src/com/mbien/opencl/CLContext.java index a82092bb..81ac58f0 100644 --- a/src/com/mbien/opencl/CLContext.java +++ b/src/com/mbien/opencl/CLContext.java @@ -1,6 +1,6 @@ package com.mbien.opencl; -import com.mbien.opencl.CLBuffer.MEM; +import com.mbien.opencl.CLBuffer.Mem; import com.sun.gluegen.runtime.BufferFactory; import com.sun.gluegen.runtime.CPU; import java.io.BufferedReader; @@ -19,7 +19,9 @@ import java.util.Map; import static com.mbien.opencl.CLException.*; /** - * + * CLContext is responsible for managing objects such as command-queues, memory, + * program and kernel objects and for executing kernels on one or more devices + * specified in the context. * @author Michael Bien */ public final class CLContext { @@ -42,30 +44,71 @@ public final class CLContext { this.queuesMap = new HashMap<CLDevice, List<CLCommandQueue>>(); } + private final void initDevices() { + + if (devices == null) { + + int sizeofDeviceID = CPU.is32Bit() ? 4 : 8; + long[] longBuffer = new long[1]; + + int ret = cl.clGetContextInfo(ID, CL.CL_CONTEXT_DEVICES, 0, null, longBuffer, 0); + checkForError(ret, "can not enumerate devices"); + + ByteBuffer deviceIDs = ByteBuffer.allocate((int) longBuffer[0]).order(ByteOrder.nativeOrder()); + ret = cl.clGetContextInfo(ID, CL.CL_CONTEXT_DEVICES, deviceIDs.capacity(), deviceIDs, null, 0); + checkForError(ret, "can not enumerate devices"); + + devices = new CLDevice[deviceIDs.capacity() / sizeofDeviceID]; + for (int i = 0; i < devices.length; i++) { + devices[i] = new CLDevice(this, CPU.is32Bit() ? deviceIDs.getInt() : deviceIDs.getLong()); + } + } + } + /** - * Creates a default context on all available devices. + * Creates a default context on all available devices (CL_DEVICE_TYPE_ALL). + * The platform to be used is implementation dependent. */ public static final CLContext create() { - return createContext(CL.CL_DEVICE_TYPE_ALL); + return createContext(null, CL.CL_DEVICE_TYPE_ALL); } /** * Creates a default context on the specified device types. + * The platform to be used is implementation dependent. */ public static final CLContext create(CLDevice.Type... deviceTypes) { + return create(null, deviceTypes); + } - int type = deviceTypes[0].CL_TYPE; - for (int i = 1; i < deviceTypes.length; i++) { - type |= deviceTypes[i].CL_TYPE; + // TODO check if driver bug, otherwise find the reason why this is not working (INVALID_VALUE with NV driver) + /** + * Creates a default context on the specified platform and with the specified + * device types. + */ + private static final CLContext create(CLPlatform platform, CLDevice.Type... deviceTypes) { + + int type = 0; + if(deviceTypes != null) { + for (int i = 0; i < deviceTypes.length; i++) { + type |= deviceTypes[i].CL_TYPE; + } } - return createContext(type); + IntBuffer properties = null; + if(platform != null) { + properties = IntBuffer.allocate(3); + properties.put(CL.CL_CONTEXT_PLATFORM).put((int)platform.ID).put(0); // TODO check if this has to be int or long + properties.rewind(); + } + + return createContext(properties, type); } - private static final CLContext createContext(long deviceType) { + private static final CLContext createContext(IntBuffer properties, long deviceType) { IntBuffer status = IntBuffer.allocate(1); - long context = CLPlatform.getLowLevelBinding().clCreateContextFromType(null, 0, deviceType, null, null, status, 0); + long context = CLPlatform.getLowLevelBinding().clCreateContextFromType(properties, deviceType, null, null, status); checkForError(status.get(), "can not create CL context"); @@ -104,14 +147,14 @@ public final class CLContext { /** * Creates a CLBuffer with the specified flags. No flags creates a MEM.READ_WRITE buffer. */ - public CLBuffer createBuffer(ByteBuffer directBuffer, MEM... flags) { - return createBuffer(directBuffer, MEM.flagsToInt(flags)); + public CLBuffer createBuffer(ByteBuffer directBuffer, Mem... flags) { + return createBuffer(directBuffer, Mem.flagsToInt(flags)); } /** * Creates a CLBuffer with the specified flags. No flags creates a MEM.READ_WRITE buffer. */ - public CLBuffer createBuffer(int size, MEM... flags) { - return createBuffer(size, MEM.flagsToInt(flags)); + public CLBuffer createBuffer(int size, Mem... flags) { + return createBuffer(size, Mem.flagsToInt(flags)); } public CLBuffer createBuffer(int size, int flags) { @@ -187,6 +230,8 @@ public final class CLContext { /** * Gets the device with maximal FLOPS from this context. + * The device speed is estimated by calulating the product of + * MAX_COMPUTE_UNITS and MAX_CLOCK_FREQUENCY. */ public CLDevice getMaxFlopsDevice() { @@ -215,29 +260,7 @@ public final class CLContext { * Returns all devices associated with this CLContext. */ public CLDevice[] getCLDevices() { - - if(devices == null) { - - int sizeofDeviceID = CPU.is32Bit()?4:8; - - long[] longBuffer = new long[1]; - - int ret; - ret = cl.clGetContextInfo(ID, CL.CL_CONTEXT_DEVICES, 0, null, longBuffer, 0); - checkForError(ret, "can not enumerate devices"); - - ByteBuffer deviceIDs = ByteBuffer.allocate((int)longBuffer[0]).order(ByteOrder.nativeOrder()); - - ret = cl.clGetContextInfo(ID, CL.CL_CONTEXT_DEVICES, deviceIDs.capacity(), deviceIDs, null, 0); - checkForError(ret, "can not enumerate devices"); - - devices = new CLDevice[deviceIDs.capacity()/sizeofDeviceID]; - for (int i = 0; i < devices.length; i++) { - devices[i] = new CLDevice(this, - CPU.is32Bit()?deviceIDs.getInt():deviceIDs.getLong()); - } - } - + initDevices(); return devices; } @@ -279,5 +302,4 @@ public final class CLContext { return hash; } - } diff --git a/src/com/mbien/opencl/CLDevice.java b/src/com/mbien/opencl/CLDevice.java index 87616516..0ad8f0e9 100644 --- a/src/com/mbien/opencl/CLDevice.java +++ b/src/com/mbien/opencl/CLDevice.java @@ -15,51 +15,6 @@ import static com.mbien.opencl.CLException.*; */ public final class CLDevice { - /** - * Enumeration for the type of a device. - */ - public enum Type { - /** - * CL_DEVICE_TYPE_CPU - */ - CPU(CL.CL_DEVICE_TYPE_CPU), - /** - * CL_DEVICE_TYPE_GPU - */ - GPU(CL.CL_DEVICE_TYPE_GPU), - /** - * CL_DEVICE_TYPE_ACCELERATOR - */ - ACCELERATOR(CL.CL_DEVICE_TYPE_ACCELERATOR), - /** - * CL_DEVICE_TYPE_DEFAULT - */ - DEFAULT(CL.CL_DEVICE_TYPE_DEFAULT); - - /** - * Value of wrapped OpenCL device type. - */ - public final int CL_TYPE; - - private Type(int CL_TYPE) { - this.CL_TYPE = CL_TYPE; - } - - public static Type valueOf(int clDeviceType) { - switch(clDeviceType) { - case(CL.CL_DEVICE_TYPE_DEFAULT): - return DEFAULT; - case(CL.CL_DEVICE_TYPE_CPU): - return CPU; - case(CL.CL_DEVICE_TYPE_GPU): - return GPU; - case(CL.CL_DEVICE_TYPE_ACCELERATOR): - return ACCELERATOR; - } - return null; - } - } - private final CL cl; private CLContext context; @@ -82,6 +37,20 @@ public final class CLDevice { public CLCommandQueue createCommandQueue() { return createCommandQueue(0); } + + public CLCommandQueue createCommandQueue(CLCommandQueue.Mode property) { + return createCommandQueue(property.CL_QUEUE_MODE); + } + + public CLCommandQueue createCommandQueue(CLCommandQueue.Mode... properties) { + int flags = 0; + if(properties != null) { + for (int i = 0; i < properties.length; i++) { + flags |= properties[i].CL_QUEUE_MODE; + } + } + return createCommandQueue(flags); + } public CLCommandQueue createCommandQueue(long properties) { if(context == null) @@ -123,41 +92,77 @@ public final class CLDevice { } /** - * Returns the maximal number of compute units. + * Returns the number of parallel compute cores on the OpenCL device. + * The minimum value is 1. */ public int getMaxComputeUnits() { return (int) getInfoLong(CL.CL_DEVICE_MAX_COMPUTE_UNITS); } /** - * Returns the maximal work group size. + * Returns the maximum number of work-items in a work-group executing + * a kernel using the data parallel execution model. + * The minimum value is 1. */ public int getMaxWorkGroupSize() { return (int) getInfoLong(CL.CL_DEVICE_MAX_WORK_GROUP_SIZE); } /** - * Returns the max clock frequency in Hz. + * Returns the maximum configured clock frequency of the device in MHz. */ public int getMaxClockFrequency() { return (int) (getInfoLong(CL.CL_DEVICE_MAX_CLOCK_FREQUENCY)); } /** - * Returns the global memory size in Bytes. + * Returns the maximum dimensions that specify the global and local work-item + * IDs used by the data parallel execution model. + * The minimum value is 3. + */ + public int getMaxWorkItemDimensions() { + return (int) getInfoLong(CL.CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS); + } + + /** + * Returns the global memory size in bytes. */ public long getGlobalMemSize() { return getInfoLong(CL.CL_DEVICE_GLOBAL_MEM_SIZE); } /** - * Returns the local memory size in Bytes. + * Returns the local memory size in bytes. */ public long getLocalMemSize() { return getInfoLong(CL.CL_DEVICE_LOCAL_MEM_SIZE); } /** + * Returns the max size in bytes of a constant buffer allocation. + * The minimum value is 64 KB. + */ + public long getMaxConstantBufferSize() { + return getInfoLong(CL.CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE); + } + + /** + * Returns true if this device is available. + */ + public boolean isAvailable() { + return getInfoLong(CL.CL_DEVICE_AVAILABLE) == CL.CL_TRUE; + } + + /** + * Returns false if the implementation does not have a compiler available to + * compile the program source. Is true if the compiler is available. + * This can be false for the OpenCL ES profile only. + */ + public boolean isCompilerAvailable() { + return getInfoLong(CL.CL_DEVICE_COMPILER_AVAILABLE) == CL.CL_TRUE; + } + + /** * Returns all device extension names as unmodifiable Set. */ public Set<String> getExtensions() { @@ -233,4 +238,49 @@ public final class CLDevice { return hash; } + /** + * Enumeration for the type of a device. + */ + public enum Type { + /** + * CL_DEVICE_TYPE_CPU + */ + CPU(CL.CL_DEVICE_TYPE_CPU), + /** + * CL_DEVICE_TYPE_GPU + */ + GPU(CL.CL_DEVICE_TYPE_GPU), + /** + * CL_DEVICE_TYPE_ACCELERATOR + */ + ACCELERATOR(CL.CL_DEVICE_TYPE_ACCELERATOR), + /** + * CL_DEVICE_TYPE_DEFAULT + */ + DEFAULT(CL.CL_DEVICE_TYPE_DEFAULT); + + /** + * Value of wrapped OpenCL device type. + */ + public final int CL_TYPE; + + private Type(int CL_TYPE) { + this.CL_TYPE = CL_TYPE; + } + + public static Type valueOf(int clDeviceType) { + switch(clDeviceType) { + case(CL.CL_DEVICE_TYPE_DEFAULT): + return DEFAULT; + case(CL.CL_DEVICE_TYPE_CPU): + return CPU; + case(CL.CL_DEVICE_TYPE_GPU): + return GPU; + case(CL.CL_DEVICE_TYPE_ACCELERATOR): + return ACCELERATOR; + } + return null; + } + } + } diff --git a/src/com/mbien/opencl/CLKernel.java b/src/com/mbien/opencl/CLKernel.java index 838f5969..3388251b 100644 --- a/src/com/mbien/opencl/CLKernel.java +++ b/src/com/mbien/opencl/CLKernel.java @@ -76,6 +76,9 @@ public class CLKernel { return BufferFactory.newDirectByteBuffer(8).putLong(value).rewind(); } + /** + * Releases all resources of this kernel from its context. + */ public void release() { int ret = cl.clReleaseKernel(ID); program.onKernelReleased(this); diff --git a/src/com/mbien/opencl/CLProgram.java b/src/com/mbien/opencl/CLProgram.java index 70656373..ff2919e8 100644 --- a/src/com/mbien/opencl/CLProgram.java +++ b/src/com/mbien/opencl/CLProgram.java @@ -21,39 +21,6 @@ public class CLProgram { private final Map<String, CLKernel> kernels; - public enum Status { - - BUILD_SUCCESS(CL.CL_BUILD_SUCCESS), - BUILD_NONE(CL.CL_BUILD_NONE), - BUILD_IN_PROGRESS(CL.CL_BUILD_IN_PROGRESS), - BUILD_ERROR(CL.CL_BUILD_ERROR); - - /** - * Value of wrapped OpenCL device type. - */ - public final int CL_BUILD_STATUS; - - private Status(int CL_BUILD_STATUS) { - this.CL_BUILD_STATUS = CL_BUILD_STATUS; - } - - public static Status valueOf(int clBuildStatus) { - switch(clBuildStatus) { - case(CL.CL_BUILD_SUCCESS): - return BUILD_SUCCESS; - case(CL.CL_BUILD_NONE): - return BUILD_NONE; - case(CL.CL_BUILD_IN_PROGRESS): - return BUILD_IN_PROGRESS; - case(CL.CL_BUILD_ERROR): - return BUILD_ERROR; -// is this a standard state? -// case (CL.CL_BUILD_PROGRAM_FAILURE): -// return BUILD_PROGRAM_FAILURE; - } - return null; - } - } CLProgram(CLContext context, String src, long contextID) { @@ -68,6 +35,76 @@ public class CLProgram { checkForError(intArray[0], "can not create program with source"); } + private final void initKernels() { + + if(kernels.isEmpty()) { + int[] intArray = new int[1]; + int ret = cl.clCreateKernelsInProgram(ID, 0, null, 0, intArray, 0); + checkForError(ret, "can not create kernels for program"); + + long[] kernelIDs = new long[intArray[0]]; + ret = cl.clCreateKernelsInProgram(ID, kernelIDs.length, kernelIDs, 0, null, 0); + checkForError(ret, "can not create kernels for program"); + + for (int i = 0; i < intArray[0]; i++) { + CLKernel kernel = new CLKernel(this, kernelIDs[i]); + kernels.put(kernel.name, kernel); + } + } + } + + // TODO serialization, program build options + + private final String getBuildInfoString(long device, int flag) { + + long[] longArray = new long[1]; + + int ret = cl.clGetProgramBuildInfo(ID, device, flag, 0, null, longArray, 0); + checkForError(ret, "on clGetProgramBuildInfo"); + + ByteBuffer bb = ByteBuffer.allocate((int)longArray[0]).order(ByteOrder.nativeOrder()); + + ret = cl.clGetProgramBuildInfo(ID, device, flag, bb.capacity(), bb, null, 0); + checkForError(ret, "on clGetProgramBuildInfo"); + + return new String(bb.array(), 0, (int)longArray[0]); + } + + private final String getProgramInfoString(int flag) { + + long[] longArray = new long[1]; + + int ret = cl.clGetProgramInfo(ID, flag, 0, null, longArray, 0); + checkForError(ret, "on clGetProgramInfo"); + + ByteBuffer bb = ByteBuffer.allocate((int)longArray[0]).order(ByteOrder.nativeOrder()); + + ret = cl.clGetProgramInfo(ID, flag, bb.capacity(), bb, null, 0); + checkForError(ret, "on clGetProgramInfo"); + + return new String(bb.array(), 0, (int)longArray[0]); + } + +// private int getProgramInfoInt(int flag) { +// +// ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()); +// +// int ret = cl.clGetProgramInfo(programID, flag, bb.capacity(), bb, null, 0); +// checkForError(ret, ""); +// +// return bb.getInt(); +// } + + private int getBuildInfoInt(long device, int flag) { + + ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()); + + int ret = cl.clGetProgramBuildInfo(ID, device, flag, bb.capacity(), bb, null, 0); + checkForError(ret, "error on clGetProgramBuildInfo"); + + return bb.getInt(); + } + /** * Builds this program for all devices associated with the context and implementation specific build options. @@ -79,6 +116,15 @@ public class CLProgram { } /** + * Builds this program for all devices associated with the context using the specified build options. + * @return this + */ + public CLProgram build(String options) { + build(null, options); + return this; + } + + /** * Builds this program for the given devices and with the specified build options. * @return this * @param devices A list of devices this program should be build on or null for all devices of its context. @@ -100,30 +146,6 @@ public class CLProgram { return this; } - /** - * Returns all kernels of this program in a unmodifiable view of a map with the kernel function names as keys. - */ - public Map<String, CLKernel> getCLKernels() { - - if(kernels.isEmpty()) { - - int[] intArray = new int[1]; - int ret = cl.clCreateKernelsInProgram(ID, 0, null, 0, intArray, 0); - checkForError(ret, "can not create kernels for program"); - - long[] kernelIDs = new long[intArray[0]]; - ret = cl.clCreateKernelsInProgram(ID, kernelIDs.length, kernelIDs, 0, null, 0); - checkForError(ret, "can not create kernels for program"); - - for (int i = 0; i < intArray[0]; i++) { - CLKernel kernel = new CLKernel(this, kernelIDs[i]); - kernels.put(kernel.name, kernel); - } - } - - return Collections.unmodifiableMap(kernels); - } - void onKernelReleased(CLKernel kernel) { this.kernels.remove(kernel.name); } @@ -147,6 +169,24 @@ public class CLProgram { } /** + * Returns the kernel with the specified name or null if not found. + */ + public CLKernel getCLKernel(String kernelName) { + initKernels(); + return kernels.get(kernelName); + } + + + /** + * Returns all kernels of this program in a unmodifiable view of a map + * with the kernel function names as keys. + */ + public Map<String, CLKernel> getCLKernels() { + initKernels(); + return Collections.unmodifiableMap(kernels); + } + + /** * Returns all devices associated with this program. */ public CLDevice[] getCLDevices() { @@ -169,22 +209,34 @@ public class CLProgram { } + /** + * Returns the build log for this program. The contents of the log are + * implementation dependent log can be an empty String. + */ public String getBuildLog(CLDevice device) { return getBuildInfoString(device.ID, CL.CL_PROGRAM_BUILD_LOG); } + /** + * Returns the build status enum for this program on the specified device. + */ public Status getBuildStatus(CLDevice device) { int clStatus = getBuildInfoInt(device.ID, CL.CL_PROGRAM_BUILD_STATUS); return Status.valueOf(clStatus); } /** - * Returns the source code of this program. Note: sources are not cached, each call of this method calls into OpenCL. + * Returns the source code of this program. Note: sources are not cached, + * each call of this method calls into OpenCL. */ public String getSource() { return getProgramInfoString(CL.CL_PROGRAM_SOURCE); } + /** + * Returns the binaries for this program in a map containing the device as key + * and the byte array as value. + */ public Map<CLDevice, byte[]> getBinaries() { CLDevice[] devices = getCLDevices(); @@ -198,7 +250,7 @@ public class CLProgram { binarySize += (int)sizes.getLong(); ByteBuffer binaries = ByteBuffer.allocate(binarySize).order(ByteOrder.nativeOrder()); - ret = cl.clGetProgramInfo(ID, CL.CL_PROGRAM_BINARIES, binaries.capacity(), binaries, null, 0); // crash, driver bug? + ret = cl.clGetProgramInfo(ID, CL.CL_PROGRAM_BINARIES, binaries.capacity(), binaries, null, 0); // TODO crash, driver bug? checkForError(ret, "on clGetProgramInfo"); Map<CLDevice, byte[]> map = new HashMap<CLDevice, byte[]>(); @@ -212,59 +264,6 @@ public class CLProgram { return map; } - - // TODO serialization, program build options - - private final String getBuildInfoString(long device, int flag) { - - long[] longArray = new long[1]; - - int ret = cl.clGetProgramBuildInfo(ID, device, flag, 0, null, longArray, 0); - checkForError(ret, "on clGetProgramBuildInfo"); - - ByteBuffer bb = ByteBuffer.allocate((int)longArray[0]).order(ByteOrder.nativeOrder()); - - ret = cl.clGetProgramBuildInfo(ID, device, flag, bb.capacity(), bb, null, 0); - checkForError(ret, "on clGetProgramBuildInfo"); - - return new String(bb.array(), 0, (int)longArray[0]); - } - - private final String getProgramInfoString(int flag) { - - long[] longArray = new long[1]; - - int ret = cl.clGetProgramInfo(ID, flag, 0, null, longArray, 0); - checkForError(ret, "on clGetProgramInfo"); - - ByteBuffer bb = ByteBuffer.allocate((int)longArray[0]).order(ByteOrder.nativeOrder()); - - ret = cl.clGetProgramInfo(ID, flag, bb.capacity(), bb, null, 0); - checkForError(ret, "on clGetProgramInfo"); - - return new String(bb.array(), 0, (int)longArray[0]); - } - -// private int getProgramInfoInt(int flag) { -// -// ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()); -// -// int ret = cl.clGetProgramInfo(programID, flag, bb.capacity(), bb, null, 0); -// checkForError(ret, ""); -// -// return bb.getInt(); -// } - - private int getBuildInfoInt(long device, int flag) { - - ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.nativeOrder()); - - int ret = cl.clGetProgramBuildInfo(ID, device, flag, bb.capacity(), bb, null, 0); - checkForError(ret, "error on clGetProgramBuildInfo"); - - return bb.getInt(); - } - @Override public boolean equals(Object obj) { if (obj == null) { @@ -290,5 +289,39 @@ public class CLProgram { hash = 37 * hash + (int) (this.ID ^ (this.ID >>> 32)); return hash; } + + public enum Status { + + BUILD_SUCCESS(CL.CL_BUILD_SUCCESS), + BUILD_NONE(CL.CL_BUILD_NONE), + BUILD_IN_PROGRESS(CL.CL_BUILD_IN_PROGRESS), + BUILD_ERROR(CL.CL_BUILD_ERROR); + + /** + * Value of wrapped OpenCL device type. + */ + public final int CL_BUILD_STATUS; + + private Status(int CL_BUILD_STATUS) { + this.CL_BUILD_STATUS = CL_BUILD_STATUS; + } + + public static Status valueOf(int clBuildStatus) { + switch(clBuildStatus) { + case(CL.CL_BUILD_SUCCESS): + return BUILD_SUCCESS; + case(CL.CL_BUILD_NONE): + return BUILD_NONE; + case(CL.CL_BUILD_IN_PROGRESS): + return BUILD_IN_PROGRESS; + case(CL.CL_BUILD_ERROR): + return BUILD_ERROR; +// is this a standard state? +// case (CL.CL_BUILD_PROGRAM_FAILURE): +// return BUILD_PROGRAM_FAILURE; + } + return null; + } + } } |