aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--resources/cl-if.cfg6
-rw-r--r--resources/cl-impl.cfg2
-rw-r--r--resources/clImplCustomCode.c34
-rw-r--r--resources/clImplCustomCode.java18
-rw-r--r--src/com/mbien/opencl/CLBuffer.java127
-rw-r--r--src/com/mbien/opencl/CLCommandQueue.java38
-rw-r--r--src/com/mbien/opencl/CLContext.java98
-rw-r--r--src/com/mbien/opencl/CLDevice.java150
-rw-r--r--src/com/mbien/opencl/CLKernel.java3
-rw-r--r--src/com/mbien/opencl/CLProgram.java257
-rw-r--r--test/com/mbien/opencl/HighLevelBindingTest.java16
-rw-r--r--test/com/mbien/opencl/LowLevelBindingTest.java2
12 files changed, 442 insertions, 309 deletions
diff --git a/resources/cl-if.cfg b/resources/cl-if.cfg
index 4d7d80f1..8a4d62d8 100644
--- a/resources/cl-if.cfg
+++ b/resources/cl-if.cfg
@@ -7,7 +7,7 @@ Import java.nio.IntBuffer
ClassJavadoc CL /**
ClassJavadoc CL * Java bindings to OpenCL, the Open Computing Language.
-ClassJavadoc CL * @autor Michael Bien
+ClassJavadoc CL * @author Michael Bien
ClassJavadoc CL */
JavaClass CL
@@ -18,12 +18,12 @@ Ignore CL_GL_.*|cl.*GL.*
Ignore clCreateContext
CustomJavaCode CL
CustomJavaCode CL /** Interface to C language function: <br> <code> cl_context clCreateContext(intptr_t * , uint32_t, cl_device_id * , void (*pfn_notify)(const char *, const void *, size_t, void *), void *, int32_t * ); </code> */
-CustomJavaCode CL public long clCreateContext(IntBuffer properties, int properties_offset, long[] devices, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret, int errcode_offset);
+CustomJavaCode CL public long clCreateContext(IntBuffer properties, long[] devices, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret);
Ignore clCreateContextFromType
CustomJavaCode CL
CustomJavaCode CL /** Interface to C language function: <br> <code> cl_context clCreateContextFromType(cl_context_properties *properties, cl_device_type device_type, void (*pfn_notify)(const char *errinfo, const void *private_info, size_t cb, void *user_data), void *user_data, cl_int *errcode_ret) ; </code> */
-CustomJavaCode CL public long clCreateContextFromType(IntBuffer properties, int properties_offset, long device_type, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret, int errcode_offset);
+CustomJavaCode CL public long clCreateContextFromType(IntBuffer properties, long device_type, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret);
Ignore clBuildProgram
CustomJavaCode CL
diff --git a/resources/cl-impl.cfg b/resources/cl-impl.cfg
index 58d06be2..cee848c8 100644
--- a/resources/cl-impl.cfg
+++ b/resources/cl-impl.cfg
@@ -9,7 +9,7 @@ Import java.nio.Buffer
ClassJavadoc CLImpl /**
ClassJavadoc CLImpl * Java bindings to OpenCL, the Open Computing Language.
-ClassJavadoc CLImpl * @autor Michael Bien
+ClassJavadoc CLImpl * @author Michael Bien
ClassJavadoc CLImpl */
ImplJavaClass CLImpl
diff --git a/resources/clImplCustomCode.c b/resources/clImplCustomCode.c
index 41e9f159..a35328dc 100644
--- a/resources/clImplCustomCode.c
+++ b/resources/clImplCustomCode.c
@@ -24,9 +24,8 @@ void createContextCallback(const char * c, const void * v, size_t s, void * o) {
* void * user_data ,
* cl_int * errcode_ret );
*/
-//__Ljava_lang_Object_2IJLjava_lang_Object_2Ljava_lang_Object_2Ljava_lang_Object_2I
JNIEXPORT jlong JNICALL
-Java_com_mbien_opencl_impl_CLImpl_clCreateContextFromType0(JNIEnv *env, jobject _unused,
+Java_com_mbien_opencl_impl_CLImpl_clCreateContextFromType1(JNIEnv *env, jobject _unused,
jobject props, jint props_byte_offset, jlong device_type, jobject cb, jobject data, jobject errcode, jint errcode_byte_offset) {
intptr_t * _props_ptr = NULL;
@@ -34,26 +33,21 @@ Java_com_mbien_opencl_impl_CLImpl_clCreateContextFromType0(JNIEnv *env, jobject
cl_context _ctx;
if (props != NULL) {
- _props_ptr = (intptr_t *) (((char*) (*env)->GetDirectBufferAddress(env, props)) + props_byte_offset);
+ _props_ptr = (void *) (((char*) (*env)->GetPrimitiveArrayCritical(env, props, NULL)) + props_byte_offset);
}
if (errcode != NULL) {
- _errcode_ptr = (int32_t *) (((char*) (*env)->GetDirectBufferAddress(env, errcode)) + errcode_byte_offset);
+ _errcode_ptr = (void *) (((char*) (*env)->GetPrimitiveArrayCritical(env, errcode, NULL)) + errcode_byte_offset);
}
//TODO callback; payload
- _ctx = clCreateContextFromType((intptr_t *) _props_ptr, (uint64_t) device_type, NULL, NULL, (int32_t *) _errcode_ptr);
+ _ctx = clCreateContextFromType((cl_context_properties *) _props_ptr, (uint64_t) device_type, NULL, NULL, (int32_t *) _errcode_ptr);
-/*
- printf(" - - - - test - - - - \n");
- cl_uint err;
- size_t deviceListSize;
-
- // get the list of GPU devices associated with context
- err = clGetContextInfo(_ctx, CL_CONTEXT_DEVICES, 0, NULL, &deviceListSize); checkStatus("getContextInfo1", err);
- cl_uint count = (cl_uint)deviceListSize / sizeof(cl_device_id);
- printf("devices: %d \n", count);
- printf(" - - - - test end - - - - \n");
-*/
+ if (errcode != NULL) {
+ (*env)->ReleasePrimitiveArrayCritical(env, errcode, _errcode_ptr, 0);
+ }
+ if (props != NULL) {
+ (*env)->ReleasePrimitiveArrayCritical(env, props, _props_ptr, 0);
+ }
return (jlong)_ctx;
}
@@ -111,14 +105,6 @@ Java_com_mbien_opencl_impl_CLImpl_clBuildProgram0(JNIEnv *env, jobject _unused,
_deviceListPtr = (void *) (((char*) (*env)->GetPrimitiveArrayCritical(env, deviceList, NULL)) + offset);
}
-/*
- printf("---------------------------------------------------------------------------\n");
- printf("deviceList: %d\n", _deviceListPtr);
- printf("_strchars_options: %d\n", _strchars_options);
- printf("deviceCount: %d\n", deviceCount);
- printf("---------------------------------------------------------------------------\n");
-*/
-
// TODO payload, callback...
_res = clBuildProgram((cl_program)program, (cl_uint)deviceCount, _deviceListPtr, _strchars_options, NULL, NULL);
diff --git a/resources/clImplCustomCode.java b/resources/clImplCustomCode.java
index 3c5e1f07..0d25ddb6 100644
--- a/resources/clImplCustomCode.java
+++ b/resources/clImplCustomCode.java
@@ -1,23 +1,25 @@
- public long clCreateContext(IntBuffer properties, int offset1, long[] devices, CreateContextCallback cb, Object userData, IntBuffer errcode_ret, int offset2) {
+ public long clCreateContext(IntBuffer properties, long[] devices, CreateContextCallback cb, Object userData, IntBuffer errcode_ret) {
throw new RuntimeException("not yet implemented, use clCreateContextFromType instead");
// return this.clCreateContext0(properties, offset1, devices, cb, null, errcode_ret, offset2);
}
- private native long clCreateContext0(IntBuffer cl_context_properties, int size, long[] devices, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret, int size2);
+ private native long clCreateContext0(Object cl_context_properties, int props_offset, long[] devices, CreateContextCallback pfn_notify, Object userData, Object errcode_ret, int err_offset);
-
- public long clCreateContextFromType(IntBuffer properties, int offset1, long device_type, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret, int offset2) {
+
+ public long clCreateContextFromType(IntBuffer properties, long device_type, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret) {
if(pfn_notify != null)
throw new RuntimeException("asynchronous execution with callback is not yet implemented, pass null through this method to block until complete.");
if(userData != null)
- System.out.println("WARNING: userData not yet implemented... ignoring");
+ System.err.println("WARNING: userData not yet implemented... ignoring");
- return this.clCreateContextFromType0(properties, offset1, device_type, pfn_notify, null, errcode_ret, offset2);
+ return this.clCreateContextFromType1(
+ BufferFactory.getArray(properties), BufferFactory.getIndirectBufferByteOffset(properties), device_type, pfn_notify, null,
+ BufferFactory.getArray(errcode_ret), BufferFactory.getIndirectBufferByteOffset(errcode_ret) );
}
- private native long clCreateContextFromType0(IntBuffer properties, int size, long device_type, CreateContextCallback pfn_notify, Object userData, IntBuffer errcode_ret, int size2);
+ private native long clCreateContextFromType1(Object properties, int props_offset, long device_type, CreateContextCallback pfn_notify, Object userData, Object errcode_ret, int err_offset);
/** Interface to C language function: <br> <code> int32_t clBuildProgram(cl_program, uint32_t, cl_device_id * , const char * , void * ); </code> */
@@ -27,7 +29,7 @@
throw new RuntimeException("asynchronous execution with callback is not yet implemented, pass null through this method to block until complete.");
if(userData != null)
- System.out.println("WARNING: userData not yet implemented... ignoring");
+ System.err.println("WARNING: userData not yet implemented... ignoring");
int listLength = 0;
if(deviceList != null)
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;
+ }
+ }
}
diff --git a/test/com/mbien/opencl/HighLevelBindingTest.java b/test/com/mbien/opencl/HighLevelBindingTest.java
index 8ae61b2a..a0a2c13d 100644
--- a/test/com/mbien/opencl/HighLevelBindingTest.java
+++ b/test/com/mbien/opencl/HighLevelBindingTest.java
@@ -1,6 +1,6 @@
package com.mbien.opencl;
-import com.mbien.opencl.CLBuffer.MEM;
+import com.mbien.opencl.CLBuffer.Mem;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Map;
@@ -35,6 +35,7 @@ public class HighLevelBindingTest {
out.println("platform info:");
out.println(" name: "+platform.getName());
+ out.println(" id: "+platform.ID);
out.println(" profile: "+platform.getProfile());
out.println(" version: "+platform.getVersion());
out.println(" vendor: "+platform.getVendor());
@@ -62,7 +63,8 @@ public class HighLevelBindingTest {
out.println(" - - - highLevelTest; global memory kernel - - - ");
- CLContext context = CLContext.create();
+// CLPlatform[] clPlatforms = CLPlatform.listCLPlatforms();
+ CLContext context = CLContext.create(/*clPlatforms[0]*/);
CLDevice[] contextDevices = context.getCLDevices();
@@ -104,9 +106,9 @@ public class HighLevelBindingTest {
fillBuffer(srcA, 23456);
fillBuffer(srcB, 46987);
- CLBuffer clBufferA = context.createBuffer(srcA, MEM.READ_ONLY);
- CLBuffer clBufferB = context.createBuffer(srcB, MEM.READ_ONLY);
- CLBuffer clBufferC = context.createBuffer(dest, MEM.WRITE_ONLY);
+ CLBuffer clBufferA = context.createBuffer(srcA, Mem.READ_ONLY);
+ CLBuffer clBufferB = context.createBuffer(srcB, Mem.READ_ONLY);
+ CLBuffer clBufferC = context.createBuffer(dest, Mem.WRITE_ONLY);
Map<String, CLKernel> kernels = program.getCLKernels();
for (CLKernel kernel : kernels.values()) {
@@ -169,8 +171,8 @@ public class HighLevelBindingTest {
CLContext context = CLContext.create();
// the CL.MEM_* flag is probably completly irrelevant in our case since we do not use a kernel in this test
- CLBuffer clBufferA = context.createBuffer(elements*SIZEOF_INT, MEM.READ_ONLY);
- CLBuffer clBufferB = context.createBuffer(elements*SIZEOF_INT, MEM.READ_ONLY);
+ CLBuffer clBufferA = context.createBuffer(elements*SIZEOF_INT, Mem.READ_ONLY);
+ CLBuffer clBufferB = context.createBuffer(elements*SIZEOF_INT, Mem.READ_ONLY);
// fill only first read buffer -> we will copy the payload to the second later.
fillBuffer(clBufferA.buffer, 12345);
diff --git a/test/com/mbien/opencl/LowLevelBindingTest.java b/test/com/mbien/opencl/LowLevelBindingTest.java
index a746f977..3776a349 100644
--- a/test/com/mbien/opencl/LowLevelBindingTest.java
+++ b/test/com/mbien/opencl/LowLevelBindingTest.java
@@ -137,7 +137,7 @@ public class LowLevelBindingTest {
int ret = CL.CL_SUCCESS;
int[] intArray = new int[1];
- long context = cl.clCreateContextFromType(null, 0, CL.CL_DEVICE_TYPE_ALL, null, null, null, 0);
+ long context = cl.clCreateContextFromType(null, CL.CL_DEVICE_TYPE_ALL, null, null, null);
out.println("context handle: "+context);
ret = cl.clGetContextInfo(context, CL.CL_CONTEXT_DEVICES, 0, null, longArray, 0);