diff options
Diffstat (limited to 'src/com/jogamp/opencl/CLContext.java')
-rw-r--r-- | src/com/jogamp/opencl/CLContext.java | 504 |
1 files changed, 504 insertions, 0 deletions
diff --git a/src/com/jogamp/opencl/CLContext.java b/src/com/jogamp/opencl/CLContext.java new file mode 100644 index 00000000..a3157777 --- /dev/null +++ b/src/com/jogamp/opencl/CLContext.java @@ -0,0 +1,504 @@ +package com.jogamp.opencl; + +import com.jogamp.opencl.CLDevice.Type; +import com.jogamp.opencl.CLMemory.Mem; +import com.jogamp.opencl.CLSampler.AddressingMode; +import com.jogamp.opencl.CLSampler.FilteringMode; +import com.jogamp.common.nio.Int64Buffer; +import com.jogamp.common.nio.PointerBuffer; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.DoubleBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.LongBuffer; +import java.nio.ShortBuffer; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import static com.jogamp.opencl.CLException.*; +import static com.jogamp.common.nio.Buffers.*; +import static com.jogamp.common.os.Platform.*; + +/** + * 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 class CLContext extends CLObject implements CLResource { + + protected CLDevice[] devices; + + protected final List<CLProgram> programs; + protected final List<CLSampler> samplers; + protected final List<CLMemory<? extends Buffer>> memoryObjects; + + protected final Map<CLDevice, List<CLCommandQueue>> queuesMap; + + protected final CLPlatform platform; + + + protected CLContext(CLPlatform platform, long contextID) { + super(CLPlatform.getLowLevelCLInterface(), contextID); + this.platform = platform; + this.programs = new ArrayList<CLProgram>(); + this.samplers = new ArrayList<CLSampler>(); + this.memoryObjects = new ArrayList<CLMemory<? extends Buffer>>(); + this.queuesMap = new HashMap<CLDevice, List<CLCommandQueue>>(); + } + + private void initDevices() { + + if (devices == null) { + + Int64Buffer deviceCount = Int64Buffer.allocateDirect(1); + + int ret = cl.clGetContextInfo(ID, CL.CL_CONTEXT_DEVICES, 0, null, deviceCount); + checkForError(ret, "can not enumerate devices"); + + ByteBuffer deviceIDs = ByteBuffer.allocateDirect((int)deviceCount.get()).order(ByteOrder.nativeOrder()); + ret = cl.clGetContextInfo(ID, CL.CL_CONTEXT_DEVICES, deviceIDs.capacity(), deviceIDs, null); + checkForError(ret, "can not enumerate devices"); + + devices = new CLDevice[deviceIDs.capacity() / (is32Bit() ? 4 : 8)]; + for (int i = 0; i < devices.length; i++) { + devices[i] = new CLDevice(this, is32Bit() ? deviceIDs.getInt() : deviceIDs.getLong()); + } + } + } + + /** + * Creates a context on all available devices (CL_DEVICE_TYPE_ALL). + * The platform to be used is implementation dependent. + */ + public static CLContext create() { + return create((CLPlatform)null, Type.ALL); + } + + /** + * Creates a context on the specified device types. + * The platform to be used is implementation dependent. + */ + public static CLContext create(CLDevice.Type... deviceTypes) { + return create(null, deviceTypes); + } + + /** + * Creates a context on the specified devices. + * The platform to be used is implementation dependent. + */ + public static CLContext create(CLDevice... devices) { + return create(null, devices); + } + + /** + * Creates a context on the specified platform on all available devices (CL_DEVICE_TYPE_ALL). + */ + public static CLContext create(CLPlatform platform) { + return create(platform, CLDevice.Type.ALL); + } + + /** + * Creates a context on the specified platform and with the specified + * device types. + */ + public static CLContext create(CLPlatform platform, CLDevice.Type... deviceTypes) { + + if(platform == null) { + platform = CLPlatform.getDefault(); + } + + long type = toDeviceBitmap(deviceTypes); + + PointerBuffer properties = setupContextProperties(platform); + return new CLContext(platform, createContextFromType(properties, type)); + } + + /** + * Creates a context on the specified platform and with the specified + * devices. + */ + public static CLContext create(CLPlatform platform, CLDevice... devices) { + + if(platform == null) { + platform = CLPlatform.getDefault(); + } + + PointerBuffer properties = setupContextProperties(platform); + CLContext context = new CLContext(platform, createContext(properties, devices)); + if(devices != null) { + for (int i = 0; i < devices.length; i++) { + devices[i].setContext(context); + } + } + return context; + } + + protected static long createContextFromType(PointerBuffer properties, long deviceType) { + + IntBuffer status = IntBuffer.allocate(1); + long context = CLPlatform.getLowLevelCLInterface().clCreateContextFromType(properties, deviceType, null, null, status); + + checkForError(status.get(), "can not create CL context"); + + return context; + } + + protected static long createContext(PointerBuffer properties, CLDevice... devices) { + + IntBuffer status = newDirectIntBuffer(1); + PointerBuffer pb = null; + if(devices != null && devices.length != 0) { + pb = PointerBuffer.allocateDirect(devices.length); + for (int i = 0; i < devices.length; i++) { + pb.put(i, devices[i].ID); + } + } + long context = CLPlatform.getLowLevelCLInterface().clCreateContext(properties, pb, null, null, status); + + checkForError(status.get(), "can not create CL context"); + + return context; + } + + private static PointerBuffer setupContextProperties(CLPlatform platform) { + + if(platform == null) { + throw new RuntimeException("no OpenCL installation found"); + } + + return (PointerBuffer)PointerBuffer.allocateDirect(3).put(CL.CL_CONTEXT_PLATFORM) + .put(platform.ID).put(0) // 0 terminated array + .rewind(); + } + + /** + * Creates a program from the given sources, the program is not build yet. + */ + public CLProgram createProgram(String src) { + CLProgram program = CLProgram.create(this, src); + programs.add(program); + return program; + } + + /** + * Creates a program and reads the source from stream, the program is not build yet. + * @throws IOException when a IOException occurred while reading or closing the stream. + */ + public CLProgram createProgram(InputStream source) throws IOException { + + if(source == null) + throw new IllegalArgumentException("input stream for program source must not be null"); + + BufferedReader reader = new BufferedReader(new InputStreamReader(source)); + StringBuilder sb = new StringBuilder(); + + String line; + try { + while ((line = reader.readLine()) != null) + sb.append(line).append("\n"); + } finally { + source.close(); + } + + return createProgram(sb.toString()); + } + + /** + * Creates a program from the given binaries, the program is not build yet. + * <br/>Creating a program will fail if:<br/> + * <ul> + * <li>the submitted binaries are invalid or can not be loaded from the OpenCL driver</li> + * <li>the binaries do not fit to the CLDevices associated with this context</li> + * <li>binaries are missing for one or more CLDevices</li> + * </ul> + */ + public CLProgram createProgram(Map<CLDevice, byte[]> binaries) { + CLProgram program = CLProgram.create(this, binaries); + programs.add(program); + return program; + } + + /** + * Creates a CLBuffer with the specified flags and element count. No flags creates a MEM.READ_WRITE buffer. + */ + public final CLBuffer<ShortBuffer> createShortBuffer(int size, Mem... flags) { + return createBuffer(newDirectShortBuffer(size), flags); + } + + /** + * Creates a CLBuffer with the specified flags and element count. No flags creates a MEM.READ_WRITE buffer. + */ + public final CLBuffer<IntBuffer> createIntBuffer(int size, Mem... flags) { + return createBuffer(newDirectIntBuffer(size), flags); + } + + /** + * Creates a CLBuffer with the specified flags and element count. No flags creates a MEM.READ_WRITE buffer. + */ + public final CLBuffer<LongBuffer> createLongBuffer(int size, Mem... flags) { + return createBuffer(newDirectLongBuffer(size), flags); + } + + /** + * Creates a CLBuffer with the specified flags and element count. No flags creates a MEM.READ_WRITE buffer. + */ + public final CLBuffer<FloatBuffer> createFloatBuffer(int size, Mem... flags) { + return createBuffer(newDirectFloatBuffer(size), flags); + } + + /** + * Creates a CLBuffer with the specified flags and element count. No flags creates a MEM.READ_WRITE buffer. + */ + public final CLBuffer<DoubleBuffer> createDoubleBuffer(int size, Mem... flags) { + return createBuffer(newDirectDoubleBuffer(size), flags); + } + + /** + * Creates a CLBuffer with the specified flags and buffer size in bytes. No flags creates a MEM.READ_WRITE buffer. + */ + public final CLBuffer<ByteBuffer> createByteBuffer(int size, Mem... flags) { + return createByteBuffer(size, Mem.flagsToInt(flags)); + } + + /** + * Creates a CLBuffer with the specified flags and buffer size in bytes. + */ + public final CLBuffer<ByteBuffer> createByteBuffer(int size, int flags) { + return createBuffer(newDirectByteBuffer(size), flags); + } + + /** + * Creates a CLBuffer with the specified flags. No flags creates a MEM.READ_WRITE buffer. + */ + public final CLBuffer<?> createBuffer(int size, Mem... flags) { + return createBuffer(size, Mem.flagsToInt(flags)); + } + + /** + * Creates a CLBuffer with the specified flags. + */ + public final CLBuffer<?> createBuffer(int size, int flags) { + CLBuffer<?> buffer = CLBuffer.create(this, size, flags); + memoryObjects.add(buffer); + return buffer; + } + + /** + * Creates a CLBuffer with the specified flags. No flags creates a MEM.READ_WRITE buffer. + */ + public final <B extends Buffer> CLBuffer<B> createBuffer(B directBuffer, Mem... flags) { + return createBuffer(directBuffer, Mem.flagsToInt(flags)); + } + + /** + * Creates a CLBuffer with the specified flags. + */ + public final <B extends Buffer> CLBuffer<B> createBuffer(B directBuffer, int flags) { + CLBuffer<B> buffer = CLBuffer.create(this, directBuffer, flags); + memoryObjects.add(buffer); + return buffer; + } + + CLCommandQueue createCommandQueue(CLDevice device, long properties) { + + CLCommandQueue queue = CLCommandQueue.create(this, device, properties); + + List<CLCommandQueue> list = queuesMap.get(device); + if(list == null) { + list = new ArrayList<CLCommandQueue>(); + queuesMap.put(device, list); + } + list.add(queue); + + return queue; + } + + public CLSampler createSampler(AddressingMode addrMode, FilteringMode filtMode, boolean normalizedCoords) { + CLSampler sampler = CLSampler.create(this, addrMode, filtMode, normalizedCoords); + samplers.add(sampler); + return sampler; + } + + void onProgramReleased(CLProgram program) { + programs.remove(program); + } + + void onMemoryReleased(CLMemory<?> buffer) { + memoryObjects.remove(buffer); + } + + void onCommandQueueReleased(CLDevice device, CLCommandQueue queue) { + List<CLCommandQueue> list = queuesMap.get(device); + list.remove(queue); + // remove empty lists from map + if(list.isEmpty()) + queuesMap.remove(device); + } + + void onSamplerReleased(CLSampler sampler) { + samplers.remove(sampler); + } + + /** + * Releases the context and all resources. + */ + public void release() { + + //release all resources + while(!programs.isEmpty()) + programs.get(0).release(); + + while(!memoryObjects.isEmpty()) + memoryObjects.get(0).release(); + + while(!samplers.isEmpty()) + samplers.get(0).release(); + + for (CLDevice device : devices) { + List<CLCommandQueue> list = queuesMap.get(device); + if(list != null) { + while(!list.isEmpty()) { + list.get(0).release(); + } + } + } + + int ret = cl.clReleaseContext(ID); + checkForError(ret, "error releasing context"); + } + + public void close() { + release(); + } + + protected void overrideContext(CLDevice device) { + device.setContext(this); + } + + /** + * Returns the CLPlatform this context is running on. + */ + @Override + public CLPlatform getPlatform() { + return platform; + } + + @Override + public CLContext getContext() { + return this; + } + + /** + * Returns a read only view of all programs associated with this context. + */ + public List<CLProgram> getPrograms() { + return Collections.unmodifiableList(programs); + } + + /** + * Returns a read only view of all allocated memory objects associated with this context. + */ + public List<CLMemory<? extends Buffer>> getMemoryObjects() { + return Collections.unmodifiableList(memoryObjects); + } + + /** + * Returns a read only view of all samplers associated with this context. + */ + public List<CLSampler> getSamplers() { + return Collections.unmodifiableList(samplers); + } + + /** + * Returns the device with maximal FLOPS from this context. + * The device speed is estimated by calculating the product of + * MAX_COMPUTE_UNITS and MAX_CLOCK_FREQUENCY. + * @see #getMaxFlopsDevice(com.jogamp.opencl.CLDevice.Type) + */ + public CLDevice getMaxFlopsDevice() { + return CLPlatform.findMaxFlopsDevice(getDevices()); + } + + /** + * Returns the device with maximal FLOPS of the specified device type from this context. + * The device speed is estimated by calculating the product of + * MAX_COMPUTE_UNITS and MAX_CLOCK_FREQUENCY. + */ + public CLDevice getMaxFlopsDevice(CLDevice.Type type) { + return CLPlatform.findMaxFlopsDevice(getDevices(), type); + } + + /** + * Returns all devices associated with this CLContext. + */ + public CLDevice[] getDevices() { + initDevices(); + return devices; + } + + /** + * Return the low level OpenCL interface. + */ + public CL getCL() { + return cl; + } + + CLDevice getDevice(long dID) { + CLDevice[] deviceArray = getDevices(); + for (int i = 0; i < deviceArray.length; i++) { + if(dID == deviceArray[i].ID) + return deviceArray[i]; + } + return null; + } + + protected static long toDeviceBitmap(Type[] deviceTypes) { + long type = 0; + if (deviceTypes != null) { + for (int i = 0; i < deviceTypes.length; i++) { + type |= deviceTypes[i].TYPE; + } + } + return type; + } + + @Override + public String toString() { + return "CLContext [id: " + ID + + " #devices: " + getDevices().length + + "]"; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final CLContext other = (CLContext) obj; + if (this.ID != other.ID) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 23 * hash + (int) (this.ID ^ (this.ID >>> 32)); + return hash; + } + +} |