#parse("main/Header.vm") #macro (documentMapFlags) * @param flags Map flags. #end package com.nativelibs4java.opencl; import com.nativelibs4java.util.Pair; import static com.nativelibs4java.opencl.CLException.error; import static com.nativelibs4java.opencl.JavaCL.*; import static com.nativelibs4java.opencl.library.OpenCLLibrary.*; import static com.nativelibs4java.opencl.library.IOpenCLLibrary.*; import static com.nativelibs4java.util.NIOUtils.directBytes; import static com.nativelibs4java.util.NIOUtils.directCopy; import java.nio.ByteBuffer; import com.nativelibs4java.opencl.library.cl_buffer_region; import com.nativelibs4java.opencl.library.IOpenCLLibrary.cl_event; import com.nativelibs4java.opencl.library.IOpenCLLibrary.cl_mem; import org.bridj.*; import java.nio.ByteOrder; import java.nio.Buffer; import com.nativelibs4java.util.NIOUtils; import org.bridj.util.Utils; import static org.bridj.Pointer.*; import static com.nativelibs4java.opencl.proxy.PointerUtils.*; /** * OpenCL Memory Buffer Object.<br> * A buffer object stores a one-dimensional collection of elements.<br> * Elements of a buffer object can be a scalar data type (such as an int, float), vector data type, or a user-defined structure.<br> * @see CLContext * @author Olivier Chafik */ public class CLBuffer<T> extends CLMem { final Object owner; final PointerIO<T> io; CLBuffer(CLContext context, long byteCount, long entityPeer, Object owner, PointerIO<T> io) { super(context, byteCount, entityPeer); this.owner = owner; this.io = io; } public Class<T> getElementClass() { return Utils.getClass(io.getTargetType()); } public int getElementSize() { return (int)io.getTargetSize(); } public long getElementCount() { return getByteCount() / getElementSize(); } /** #documentCallsFunction("clEnqueueMapBuffer") #documentQueue() #documentMapFlags() #documentEventsToWaitForAndReturn() */ public Pointer<T> map(CLQueue queue, MapFlags flags, CLEvent... eventsToWaitFor) throws CLException.MapFailure { return map(queue, flags, 0, getElementCount(), true, eventsToWaitFor).getFirst(); } /** #documentCallsFunction("clEnqueueMapBuffer") #documentQueue() #documentMapFlags() * @param offset offset in the {@link CLBuffer} * @param length length to write (in bytes) #documentEventsToWaitForAndReturn() */ public Pointer<T> map(CLQueue queue, MapFlags flags, long offset, long length, CLEvent... eventsToWaitFor) throws CLException.MapFailure { return map(queue, flags, offset, length, true, eventsToWaitFor).getFirst(); } /** #documentCallsFunction("clEnqueueMapBuffer") #documentQueue() #documentMapFlags() #documentEventsToWaitForAndReturn() */ public Pair<Pointer<T>, CLEvent> mapLater(CLQueue queue, MapFlags flags, CLEvent... eventsToWaitFor) throws CLException.MapFailure { return map(queue, flags, 0, getElementCount(), false, eventsToWaitFor); } /** #documentCallsFunction("clEnqueueMapBuffer") #documentQueue() #documentMapFlags() * @param offset offset in the {@link CLBuffer} * @param length length to write (in bytes) #documentEventsToWaitForAndReturn() */ public Pair<Pointer<T>, CLEvent> mapLater(CLQueue queue, MapFlags flags, long offset, long length, CLEvent... eventsToWaitFor) throws CLException.MapFailure { return map(queue, flags, offset, length, false, eventsToWaitFor); } /** #documentCallsFunction("clEnqueueFillBuffer") #documentQueue() * @param pattern Data pattern to fill the buffer with. #documentEventsToWaitForAndReturn() */ public CLEvent fillBuffer(CLQueue queue, Pointer<T> pattern, CLEvent... eventsToWaitFor) { return fillBuffer(queue, pattern, pattern.getValidElements(), 0, getElementCount(), eventsToWaitFor); } /** #documentCallsFunction("clEnqueueFillBuffer") * @param pattern Data pattern to fill the buffer with. * @param patternLength Length in elements (not in bytes) of the pattern to use. * @param offset Offset in elements where to start filling the pattern. * @param length Length in elements of the fill (must be a multiple of patternLength). #documentEventsToWaitForAndReturn() */ public CLEvent fillBuffer(CLQueue queue, Pointer<T> pattern, long patternLength, long offset, long length, CLEvent... eventsToWaitFor) { context.getPlatform().requireMinVersionValue("clEnqueueFillBuffer", 1.2); checkBounds(offset, length); check(pattern != null, "Null pattern!"); long validPatternElements = pattern.getValidElements(); check(validPatternElements < 0 || patternLength <= validPatternElements, "Pattern length exceeds the valid pattern elements count (%d > %d)", patternLength, validPatternElements); check(length % patternLength == 0, "Fill length must be a multiple of pattern length"); #declareReusablePtrsAndEventsInOut() error(CL.clEnqueueFillBuffer( queue.getEntity(), getEntity(), getPeer(pattern), patternLength * getElementSize(), offset * getElementSize(), length * getElementSize(), #eventsInOutArgsRaw() )); #returnEventOut("queue") } /** * Returns a pointer to native memory large enough for this buffer's data, and with a compatible byte ordering. */ public Pointer<T> allocateCompatibleMemory(CLDevice device) { return allocateArray(io, getElementCount()).order(device.getKernelsDefaultByteOrder()); } public PointerIO<T> getIO() { return io; } /** #documentCallsFunction("clEnqueueReadBuffer") */ public Pointer<T> read(CLQueue queue, CLEvent... eventsToWaitFor) { Pointer<T> out = allocateCompatibleMemory(queue.getDevice()); read(queue, out, true, eventsToWaitFor); return out; } /** #documentCallsFunction("clEnqueueReadBuffer") */ public Pointer<T> read(CLQueue queue, long offset, long length, CLEvent... eventsToWaitFor) { Pointer<T> out = allocateCompatibleMemory(queue.getDevice()); read(queue, offset, length, out, true, eventsToWaitFor); return out; } protected void checkBounds(long offset, long length) { if (offset + length * getElementSize() > getByteCount()) throw new IndexOutOfBoundsException("Trying to map a region of memory object outside allocated range"); } /** #documentCallsFunction("clCreateSubBuffer") * Can be used to create a new buffer object (referred to as a sub-buffer object) from an existing buffer object. * @param usage is used to specify allocation and usage information about the image memory object being created and is described in table 5.3 of the OpenCL spec. * @param offset * @param length length in bytes * @since OpenCL 1.1 * @return sub-buffer that is a "window" of this buffer starting at the provided offset, with the provided length */ public CLBuffer<T> createSubBuffer(Usage usage, long offset, long length) { context.getPlatform().requireMinVersionValue("clCreateSubBuffer", 1.1); int s = getElementSize(); cl_buffer_region region = new cl_buffer_region().origin(s * offset).size(s * length); #declareReusablePtrsAndPErr() long mem = CL.clCreateSubBuffer(getEntity(), usage.getIntFlags(), CL_BUFFER_CREATE_TYPE_REGION, getPeer(getPointer(region)), getPeer(pErr)); #checkPErr() return mem == 0 ? null : new CLBuffer<T>(context, length * s, mem, null, io); } /** * enqueues a command to copy a buffer object identified by src_buffer to another buffer object identified by destination. * @param destination destination buffer object #documentEventsToWaitForAndReturn() */ public CLEvent copyTo(CLQueue queue, CLMem destination, CLEvent... eventsToWaitFor) { return copyTo(queue, 0, getElementCount(), destination, 0, eventsToWaitFor); } /** #documentCallsFunction("clEnqueueCopyBuffer") * enqueues a command to copy a buffer object identified by src_buffer to another buffer object identified by destination. #documentQueue() * @param srcOffset * @param length length in bytes * @param destination destination buffer object * @param destOffset #documentEventsToWaitForAndReturn() */ public CLEvent copyTo(CLQueue queue, long srcOffset, long length, CLMem destination, long destOffset, CLEvent... eventsToWaitFor) { long byteCount = getByteCount(), destByteCount = destination.getByteCount(), eltSize = getElementSize(), actualSrcOffset = srcOffset * eltSize, actualDestOffset = destOffset * eltSize, actualLength = length * eltSize; if ( actualSrcOffset < 0 || actualSrcOffset >= byteCount || actualSrcOffset + actualLength > byteCount || actualDestOffset < 0 || actualDestOffset >= destByteCount || actualDestOffset + actualLength > destByteCount ) throw new IndexOutOfBoundsException("Invalid copy parameters : srcOffset = " + srcOffset + ", destOffset = " + destOffset + ", length = " + length + " (element size = " + eltSize + ", source byte count = " + byteCount + ", destination byte count = " + destByteCount + ")"); #declareReusablePtrsAndEventsInOut() error(CL.clEnqueueCopyBuffer( queue.getEntity(), getEntity(), destination.getEntity(), actualSrcOffset, actualDestOffset, actualLength, #eventsInOutArgsRaw() )); #returnEventOut("queue") } /** #documentCallsFunction("clEnqueueMapBuffer") */ protected Pair<Pointer<T>, CLEvent> map(CLQueue queue, MapFlags flags, long offset, long length, boolean blocking, CLEvent... eventsToWaitFor) { if (flags == MapFlags.WriteInvalidateRegion) { context.getPlatform().requireMinVersionValue("CL_MAP_WRITE_INVALIDATE_REGION", 1.2); } checkBounds(offset, length); #declareReusablePtrsAndEventsInOutBlockable() #declarePErr() long mappedPeer = CL.clEnqueueMapBuffer( queue.getEntity(), getEntity(), blocking ? CL_TRUE : CL_FALSE, flags.value(), offset * getElementSize(), length * getElementSize(), #eventsInOutArgsRaw(), getPeer(pErr) ); #checkPErr() if (mappedPeer == 0) return null; return new Pair<Pointer<T>, CLEvent>( pointerToAddress(mappedPeer, io).validElements(length).order(queue.getDevice().getKernelsDefaultByteOrder()), #eventOutWrapper("queue") ); } /** #documentCallsFunction("clEnqueueUnmapMemObject") #documentQueue() * @param buffer #documentEventsToWaitForAndReturn() */ public CLEvent unmap(CLQueue queue, Pointer<T> buffer, CLEvent... eventsToWaitFor) { #declareReusablePtrsAndEventsInOut(); error(CL.clEnqueueUnmapMemObject(queue.getEntity(), getEntity(), getPeer(buffer), #eventsInOutArgsRaw())); #returnEventOut("queue") } /** #documentCallsFunction("clEnqueueReadBuffer") * @deprecated use {@link CLBuffer#read(CLQueue, Pointer, boolean, CLEvent[])} instead #documentQueue() * @param out output buffer * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event) #documentEventsToWaitForAndReturn() */ @Deprecated public CLEvent read(CLQueue queue, Buffer out, boolean blocking, CLEvent... eventsToWaitFor) { return read(queue, 0, -1, out, blocking, eventsToWaitFor); } /** #documentCallsFunction("clEnqueueReadBuffer") #documentQueue() * @param out output buffer * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event) #documentEventsToWaitForAndReturn() */ public CLEvent read(CLQueue queue, Pointer<T> out, boolean blocking, CLEvent... eventsToWaitFor) { return read(queue, 0, -1, out, blocking, eventsToWaitFor); } /** #documentCallsFunction("clEnqueueReadBuffer") * @deprecated use {@link CLBuffer#read(CLQueue, long, long, Pointer, boolean, CLEvent[])} instead #documentQueue() * @param offset offset in the {@link CLBuffer} * @param length length to write (in bytes) * @param out output buffer * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event) #documentEventsToWaitForAndReturn() */ @Deprecated public CLEvent read(CLQueue queue, long offset, long length, Buffer out, boolean blocking, CLEvent... eventsToWaitFor) { if (out == null) throw new IllegalArgumentException("Null output buffer !"); if (out.isReadOnly()) throw new IllegalArgumentException("Output buffer for read operation is read-only !"); boolean indirect = !out.isDirect(); Pointer<T> ptr = null; if (indirect) { ptr = allocateArray(io, length).order(queue.getDevice().getKernelsDefaultByteOrder()); blocking = true; } else { ptr = (Pointer)pointerToBuffer(out); } CLEvent ret = read(queue, offset, length, ptr, blocking, eventsToWaitFor); if (indirect) NIOUtils.put(ptr.getBuffer(), out); return ret; } /** #documentCallsFunction("clEnqueueReadBuffer") #documentQueue() * @param offset offset in the {@link CLBuffer} * @param length length to write (in bytes) * @param out output buffer * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event) #documentEventsToWaitForAndReturn() */ public CLEvent read(CLQueue queue, long offset, long length, Pointer<T> out, boolean blocking, CLEvent... eventsToWaitFor) { if (out == null) throw new IllegalArgumentException("Null output pointer !"); if (length < 0) { if (isGL) { length = out.getValidElements(); } if (length < 0) { length = getElementCount(); long s = out.getValidElements(); if (length > s && s >= 0) length = s; } } #declareReusablePtrsAndEventsInOutBlockable() error(CL.clEnqueueReadBuffer( queue.getEntity(), getEntity(), blocking ? CL_TRUE : 0, offset * getElementSize(), length * getElementSize(), getPeer(out), #eventsInOutArgsRaw() )); #returnEventOut("queue") } /** #documentCallsFunction("clEnqueueWriteBuffer") * @deprecated use {@link CLBuffer#write(CLQueue, Pointer, boolean, CLEvent[])} instead #documentQueue() * @param in input buffer * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event) #documentEventsToWaitForAndReturn() */ @Deprecated public CLEvent write(CLQueue queue, Buffer in, boolean blocking, CLEvent... eventsToWaitFor) { return write(queue, 0, -1, in, blocking, eventsToWaitFor); } /** #documentCallsFunction("clEnqueueWriteBuffer") #documentQueue() * @param in input buffer * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event) #documentEventsToWaitForAndReturn() */ public CLEvent write(CLQueue queue, Pointer<T> in, boolean blocking, CLEvent... eventsToWaitFor) { return write(queue, 0, -1, in, blocking, eventsToWaitFor); } /** #documentCallsFunction("clEnqueueWriteBuffer") * @deprecated use {@link CLBuffer#write(CLQueue, long, long, Pointer, boolean, CLEvent[])} instead #documentQueue() * @param offset offset in the {@link CLBuffer} * @param length length to write (in bytes) * @param in input buffer * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event) #documentEventsToWaitForAndReturn() */ @Deprecated public CLEvent write(CLQueue queue, long offset, long length, Buffer in, boolean blocking, CLEvent... eventsToWaitFor) { if (in == null) throw new IllegalArgumentException("Null input buffer !"); boolean indirect = !in.isDirect(); Pointer<T> ptr = null; if (indirect) { ptr = allocateArray(io, length).order(queue.getDevice().getKernelsDefaultByteOrder()); ptr.setValues(in); blocking = true; } else { ptr = (Pointer)pointerToBuffer(in); } return write(queue, offset, length, ptr, blocking, eventsToWaitFor); } /** #documentCallsFunction("clEnqueueWriteBuffer") #documentQueue() * @param offset offset in the {@link CLBuffer} * @param length length to write (in bytes) * @param in input buffer * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event) #documentEventsToWaitForAndReturn() */ public CLEvent write(CLQueue queue, long offset, long length, Pointer<T> in, boolean blocking, CLEvent... eventsToWaitFor) { if (length == 0) return null; if (in == null) throw new IllegalArgumentException("Null input pointer !"); if (length < 0) { if (isGL) length = in.getValidElements(); if (length < 0) { length = getElementCount(); long s = in.getValidElements(); if (length > s && s >= 0) length = s; } } #declareReusablePtrsAndEventsInOutBlockable() error(CL.clEnqueueWriteBuffer( queue.getEntity(), getEntity(), blocking ? CL_TRUE : CL_FALSE, offset * getElementSize(), length * getElementSize(), getPeer(in), #eventsInOutArgsRaw() )); #returnEventOut("queue") } /** #documentCallsFunction("clEnqueueWriteBuffer") #documentQueue() * @param offset offset in the {@link CLBuffer} * @param length length to write (in bytes) * @param in input buffer * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event) #documentEventsToWaitForAndReturn() */ public CLEvent writeBytes(CLQueue queue, long offset, long length, ByteBuffer in, boolean blocking, CLEvent... eventsToWaitFor) { return writeBytes(queue, offset, length, pointerToBuffer(in), blocking, eventsToWaitFor); } /** #documentCallsFunction("clEnqueueWriteBuffer") #documentQueue() * @param offset offset in the {@link CLBuffer} * @param length length to write (in bytes) * @param in input buffer * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event) #documentEventsToWaitForAndReturn() */ public CLEvent writeBytes(CLQueue queue, long offset, long length, Pointer<?> in, boolean blocking, CLEvent... eventsToWaitFor) { if (in == null) throw new IllegalArgumentException("Null input pointer !"); #declareReusablePtrsAndEventsInOutBlockable() error(CL.clEnqueueWriteBuffer( queue.getEntity(), getEntity(), blocking ? CL_TRUE : 0, offset, length, getPeer(in), #eventsInOutArgsRaw() )); #returnEventOut("queue") } private <T extends CLMem> T copyGLMark(T mem) { mem.isGL = this.isGL; return mem; } public CLBuffer<T> emptyClone(CLMem.Usage usage) { return (CLBuffer)getContext().createBuffer(usage, io, getElementCount()); } #foreach ($prim in $primitivesNoBool) public CLBuffer<${prim.WrapperName}> asCL${prim.BufferName}() { return as(${prim.WrapperName}.class); } #end public <T> CLBuffer<T> as(Class<T> newTargetType) { long mem = getEntity(); assert mem != 0; error(CL.clRetainMemObject(mem)); PointerIO<T> newIO = PointerIO.getInstance(newTargetType); return copyGLMark(new CLBuffer<T>(context, getByteCount(), mem, owner, newIO)); } /** #documentCallsFunction("clEnqueueCopyBuffer") #documentQueue() * @param destination destination buffer object #documentEventsToWaitForAndReturn() */ public CLEvent copyTo(CLQueue queue, CLBuffer destination, CLEvent... eventsToWaitFor) { return copyBytesTo(queue, destination, 0, 0, getByteCount(), eventsToWaitFor); } /** #documentCallsFunction("clEnqueueCopyBuffer") #documentQueue() * @param destination destination buffer object * @param sourceByteOffset byte offset in the source * @param destinationByteOffset byte offset in the destination * @param byteCount number of bytes to copy #documentEventsToWaitForAndReturn() */ public CLEvent copyBytesTo(CLQueue queue, CLBuffer destination, long sourceByteOffset, long destinationByteOffset, long byteCount, CLEvent... eventsToWaitFor) { #declareReusablePtrsAndEventsInOut() error(CL.clEnqueueCopyBuffer( queue.getEntity(), getEntity(), destination.getEntity(), sourceByteOffset, destinationByteOffset, byteCount, #eventsInOutArgsRaw())); #returnEventOut("queue") } /** #documentCallsFunction("clEnqueueCopyBuffer") #documentQueue() * @param destination destination buffer object * @param sourceElementOffset element offset in the source * @param destinationElementOffset element offset in the destination * @param elementCount number of elements to copy #documentEventsToWaitForAndReturn() */ public CLEvent copyElementsTo(CLQueue queue, CLBuffer destination, long sourceElementOffset, long destinationElementOffset, long elementCount, CLEvent... eventsToWaitFor) { long elementSize = getElementSize(); return copyBytesTo(queue, destination, sourceElementOffset * elementSize, destinationElementOffset * elementSize, elementCount * elementSize, eventsToWaitFor); } }