001/*
002 * JavaCL - Java API and utilities for OpenCL
003 * http://javacl.googlecode.com/
004 *
005 * Copyright (c) 2009-2013, Olivier Chafik (http://ochafik.com/)
006 * All rights reserved.
007 *
008 * Redistribution and use in source and binary forms, with or without
009 * modification, are permitted provided that the following conditions are met:
010 * 
011 *     * Redistributions of source code must retain the above copyright
012 *       notice, this list of conditions and the following disclaimer.
013 *     * Redistributions in binary form must reproduce the above copyright
014 *       notice, this list of conditions and the following disclaimer in the
015 *       documentation and/or other materials provided with the distribution.
016 *     * Neither the name of Olivier Chafik nor the
017 *       names of its contributors may be used to endorse or promote products
018 *       derived from this software without specific prior written permission.
019 * 
020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY
021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030 */
031        
032
033
034
035
036        
037
038        
039        
040
041
042
043        
044
045        
046        
047        
048
049        
050
051
052package com.nativelibs4java.opencl;
053import com.nativelibs4java.util.Pair;
054import static com.nativelibs4java.opencl.CLException.error;
055import static com.nativelibs4java.opencl.JavaCL.*;
056import static com.nativelibs4java.opencl.library.OpenCLLibrary.*;
057import static com.nativelibs4java.opencl.library.IOpenCLLibrary.*;
058import static com.nativelibs4java.util.NIOUtils.directBytes;
059import static com.nativelibs4java.util.NIOUtils.directCopy;
060
061import java.nio.ByteBuffer;
062
063import com.nativelibs4java.opencl.library.cl_buffer_region;
064import com.nativelibs4java.opencl.library.IOpenCLLibrary.cl_event;
065import com.nativelibs4java.opencl.library.IOpenCLLibrary.cl_mem;
066import org.bridj.*;
067import java.nio.ByteOrder;
068import java.nio.Buffer;
069import com.nativelibs4java.util.NIOUtils;
070import org.bridj.util.Utils;
071import static org.bridj.Pointer.*;
072import static com.nativelibs4java.opencl.proxy.PointerUtils.*;
073
074
075/**
076 * OpenCL Memory Buffer Object.<br>
077 * A buffer object stores a one-dimensional collection of elements.<br>
078 * 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>
079 * @see CLContext
080 * @author Olivier Chafik
081 */
082public class CLBuffer<T> extends CLMem {
083        final Object owner;
084    final PointerIO<T> io;
085    
086        CLBuffer(CLContext context, long byteCount, long entityPeer, Object owner, PointerIO<T> io) {
087        super(context, byteCount, entityPeer);
088                this.owner = owner;
089        this.io = io;
090        }
091    
092        public Class<T> getElementClass() {
093        return Utils.getClass(io.getTargetType());
094    }
095        public int getElementSize() {
096        return (int)io.getTargetSize();
097    }
098        public long getElementCount() {
099        return getByteCount() / getElementSize();
100    }
101        /**
102  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueMapBuffer.html">clEnqueueMapBuffer</a>.<br>
103  * @param queue Execution queue for this operation.
104  * @param flags Map flags.
105         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
106     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
107        */
108        public Pointer<T> map(CLQueue queue, MapFlags flags, CLEvent... eventsToWaitFor) throws CLException.MapFailure {
109                return map(queue, flags, 0, getElementCount(), true, eventsToWaitFor).getFirst();
110    }
111        /**
112  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueMapBuffer.html">clEnqueueMapBuffer</a>.<br>
113  * @param queue Execution queue for this operation.
114  * @param flags Map flags.
115   * @param offset offset in the {@link CLBuffer}
116   * @param length length to write (in bytes)
117         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
118     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
119        */
120        public Pointer<T> map(CLQueue queue, MapFlags flags, long offset, long length, CLEvent... eventsToWaitFor) throws CLException.MapFailure {
121                return map(queue, flags, offset, length, true, eventsToWaitFor).getFirst();
122    }
123    
124        /**
125  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueMapBuffer.html">clEnqueueMapBuffer</a>.<br>
126  * @param queue Execution queue for this operation.
127  * @param flags Map flags.
128         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
129     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
130        */
131        public Pair<Pointer<T>, CLEvent> mapLater(CLQueue queue, MapFlags flags, CLEvent... eventsToWaitFor) throws CLException.MapFailure {
132                return map(queue, flags, 0, getElementCount(), false, eventsToWaitFor);
133    }
134        /**
135  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueMapBuffer.html">clEnqueueMapBuffer</a>.<br>
136  * @param queue Execution queue for this operation.
137  * @param flags Map flags.
138   * @param offset offset in the {@link CLBuffer}
139   * @param length length to write (in bytes)
140         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
141     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
142        */
143        public Pair<Pointer<T>, CLEvent> mapLater(CLQueue queue, MapFlags flags, long offset, long length, CLEvent... eventsToWaitFor) throws CLException.MapFailure {
144                return map(queue, flags, offset, length, false, eventsToWaitFor);
145    }
146
147    /**
148  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueFillBuffer.html">clEnqueueFillBuffer</a>.<br>
149  * @param queue Execution queue for this operation.
150     * @param pattern Data pattern to fill the buffer with.
151         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
152     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
153     */
154    public CLEvent fillBuffer(CLQueue queue, Pointer<T> pattern, CLEvent... eventsToWaitFor) {
155        return fillBuffer(queue, pattern, pattern.getValidElements(), 0, getElementCount(), eventsToWaitFor);
156    }
157
158    /**
159  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueFillBuffer.html">clEnqueueFillBuffer</a>.<br>
160     * @param pattern Data pattern to fill the buffer with.
161     * @param patternLength Length in elements (not in bytes) of the pattern to use.
162     * @param offset Offset in elements where to start filling the pattern.
163     * @param length Length in elements of the fill (must be a multiple of patternLength).
164         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
165     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
166     */
167    public CLEvent fillBuffer(CLQueue queue, Pointer<T> pattern, long patternLength, long offset, long length, CLEvent... eventsToWaitFor) {
168                context.getPlatform().requireMinVersionValue("clEnqueueFillBuffer", 1.2);
169                checkBounds(offset, length);
170                check(pattern != null, "Null pattern!");
171                long validPatternElements = pattern.getValidElements();
172                check(validPatternElements < 0 || patternLength <= validPatternElements,
173                        "Pattern length exceeds the valid pattern elements count (%d > %d)",
174                        patternLength, validPatternElements);
175                check(length % patternLength == 0, "Fill length must be a multiple of pattern length");
176
177                                ReusablePointers ptrs = ReusablePointers.get();
178                int[] eventsInCount = ptrs.int1Array;
179        Pointer<cl_event> eventsIn = 
180                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
181                Pointer<cl_event> eventOut = 
182                eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
183                ? null 
184                : ptrs.event_out;
185                error(CL.clEnqueueFillBuffer(
186                        queue.getEntity(),
187                        getEntity(),
188                        getPeer(pattern),
189                        patternLength * getElementSize(),
190                        offset * getElementSize(),
191                        length * getElementSize(),
192                          eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)              ));
193         return  CLEvent.createEventFromPointer(queue, eventOut) ;     }
194
195    /**
196     * Returns a pointer to native memory large enough for this buffer's data, and with a compatible byte ordering. 
197     */
198    public Pointer<T> allocateCompatibleMemory(CLDevice device) {
199        return allocateArray(io, getElementCount()).order(device.getKernelsDefaultByteOrder());
200    }
201
202        public PointerIO<T> getIO() {
203                return io;
204        }
205    
206        /**
207  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueReadBuffer.html">clEnqueueReadBuffer</a>.<br>
208        */
209        public Pointer<T> read(CLQueue queue, CLEvent... eventsToWaitFor) {
210        Pointer<T> out = allocateCompatibleMemory(queue.getDevice());
211        read(queue, out, true, eventsToWaitFor);
212                return out;
213        }
214        /**
215  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueReadBuffer.html">clEnqueueReadBuffer</a>.<br>
216        */
217        public Pointer<T> read(CLQueue queue, long offset, long length, CLEvent... eventsToWaitFor) {
218                Pointer<T> out = allocateCompatibleMemory(queue.getDevice());
219        read(queue, offset, length, out, true, eventsToWaitFor);
220                return out;
221        }
222
223        protected void checkBounds(long offset, long length) {
224                if (offset + length * getElementSize() > getByteCount())
225                        throw new IndexOutOfBoundsException("Trying to map a region of memory object outside allocated range");
226        }
227
228        /**
229  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clCreateSubBuffer.html">clCreateSubBuffer</a>.<br>
230         * Can be used to create a new buffer object (referred to as a sub-buffer object) from an existing buffer object.
231         * @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.
232         * @param offset
233         * @param length length in bytes
234         * @since OpenCL 1.1
235         * @return sub-buffer that is a "window" of this buffer starting at the provided offset, with the provided length
236         */
237        public CLBuffer<T> createSubBuffer(Usage usage, long offset, long length) {
238                context.getPlatform().requireMinVersionValue("clCreateSubBuffer", 1.1);
239                int s = getElementSize();
240                cl_buffer_region region = new cl_buffer_region().origin(s * offset).size(s * length);
241                                ReusablePointers ptrs = ReusablePointers.get();
242                Pointer<Integer> pErr = ptrs.pErr;
243            long mem = CL.clCreateSubBuffer(getEntity(), usage.getIntFlags(), CL_BUFFER_CREATE_TYPE_REGION, getPeer(getPointer(region)), getPeer(pErr));
244                error(pErr.getInt());
245        return mem == 0 ? null : new CLBuffer<T>(context, length * s, mem, null, io);
246        }
247        
248        /**
249         * enqueues a command to copy a buffer object identified by src_buffer to another buffer object identified by destination.
250         * @param destination destination buffer object
251         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
252     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
253         */
254        public CLEvent copyTo(CLQueue queue, CLMem destination, CLEvent... eventsToWaitFor) {
255                return copyTo(queue, 0, getElementCount(), destination, 0, eventsToWaitFor);    
256        }
257        
258        /**
259  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueCopyBuffer.html">clEnqueueCopyBuffer</a>.<br>
260         * enqueues a command to copy a buffer object identified by src_buffer to another buffer object identified by destination.
261  * @param queue Execution queue for this operation.
262         * @param srcOffset
263         * @param length length in bytes
264         * @param destination destination buffer object
265         * @param destOffset
266         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
267     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
268         */
269        public CLEvent copyTo(CLQueue queue, long srcOffset, long length, CLMem destination, long destOffset, CLEvent... eventsToWaitFor) {
270                long 
271                        byteCount = getByteCount(),
272                        destByteCount = destination.getByteCount(),
273                        eltSize = getElementSize(),
274                        actualSrcOffset = srcOffset * eltSize, 
275                        actualDestOffset = destOffset * eltSize, 
276                        actualLength = length * eltSize;
277                
278                if (    actualSrcOffset < 0 ||
279                        actualSrcOffset >= byteCount ||
280                        actualSrcOffset + actualLength > byteCount ||
281                        actualDestOffset < 0 ||
282                        actualDestOffset >= destByteCount ||
283                        actualDestOffset + actualLength > destByteCount
284                )
285                        throw new IndexOutOfBoundsException("Invalid copy parameters : srcOffset = " + srcOffset + ", destOffset = " + destOffset + ", length = " + length + " (element size = " + eltSize + ", source byte count = " + byteCount + ", destination byte count = " + destByteCount + ")"); 
286                
287                                ReusablePointers ptrs = ReusablePointers.get();
288                int[] eventsInCount = ptrs.int1Array;
289        Pointer<cl_event> eventsIn = 
290                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
291                Pointer<cl_event> eventOut = 
292                eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
293                ? null 
294                : ptrs.event_out;
295        error(CL.clEnqueueCopyBuffer(
296                        queue.getEntity(),
297                        getEntity(),
298                        destination.getEntity(),
299                        actualSrcOffset,
300                        actualDestOffset,
301                        actualLength,
302                          eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)              ));
303                 return  CLEvent.createEventFromPointer(queue, eventOut) ;      }
304
305        /**
306  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueMapBuffer.html">clEnqueueMapBuffer</a>.<br>
307        */
308        protected Pair<Pointer<T>, CLEvent> map(CLQueue queue, MapFlags flags, long offset, long length, boolean blocking, CLEvent... eventsToWaitFor) {
309        if (flags == MapFlags.WriteInvalidateRegion) {
310            context.getPlatform().requireMinVersionValue("CL_MAP_WRITE_INVALIDATE_REGION", 1.2);
311        }
312                checkBounds(offset, length);
313                                ReusablePointers ptrs = ReusablePointers.get();
314                int[] eventsInCount = ptrs.int1Array;
315        Pointer<cl_event> eventsIn = 
316                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
317                Pointer<cl_event> eventOut = 
318                blocking || eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
319                ? null 
320                : ptrs.event_out;
321                        Pointer<Integer> pErr = ptrs.pErr;
322        long mappedPeer = CL.clEnqueueMapBuffer(
323                        queue.getEntity(), 
324                        getEntity(), 
325                        blocking ? CL_TRUE : CL_FALSE,
326                        flags.value(),
327                        offset * getElementSize(),
328            length * getElementSize(),
329              eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)  ,
330                        getPeer(pErr)
331                );
332                        error(pErr.getInt());
333                if (mappedPeer == 0)
334                        return null;
335        return new Pair<Pointer<T>, CLEvent>(
336                        pointerToAddress(mappedPeer, io).validElements(length).order(queue.getDevice().getKernelsDefaultByteOrder()),
337                         CLEvent.createEventFromPointer(queue, eventOut)                );
338    }
339
340    /**
341  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueUnmapMemObject.html">clEnqueueUnmapMemObject</a>.<br>
342  * @param queue Execution queue for this operation.
343   * @param buffer
344         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
345     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
346        */
347        public CLEvent unmap(CLQueue queue, Pointer<T> buffer, CLEvent... eventsToWaitFor) {
348                        ReusablePointers ptrs = ReusablePointers.get();
349                int[] eventsInCount = ptrs.int1Array;
350        Pointer<cl_event> eventsIn = 
351                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
352                Pointer<cl_event> eventOut = 
353                eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
354                ? null 
355                : ptrs.event_out;
356;
357        error(CL.clEnqueueUnmapMemObject(queue.getEntity(), getEntity(), getPeer(buffer),   eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)  ));
358                 return  CLEvent.createEventFromPointer(queue, eventOut) ;     }
359
360    /**
361  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueReadBuffer.html">clEnqueueReadBuffer</a>.<br>
362     * @deprecated use {@link CLBuffer#read(CLQueue, Pointer, boolean, CLEvent[])} instead
363  * @param queue Execution queue for this operation.
364   * @param out output buffer
365   * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event)
366         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
367     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
368     */
369    @Deprecated
370        public CLEvent read(CLQueue queue, Buffer out, boolean blocking, CLEvent... eventsToWaitFor) {
371                return read(queue, 0, -1, out, blocking, eventsToWaitFor);
372    }
373    
374        /**
375  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueReadBuffer.html">clEnqueueReadBuffer</a>.<br>
376  * @param queue Execution queue for this operation.
377   * @param out output buffer
378   * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event)
379         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
380     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
381        */
382        public CLEvent read(CLQueue queue, Pointer<T> out, boolean blocking, CLEvent... eventsToWaitFor) {
383        return read(queue, 0, -1, out, blocking, eventsToWaitFor);
384        }
385
386        /**
387  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueReadBuffer.html">clEnqueueReadBuffer</a>.<br>
388         * @deprecated use {@link CLBuffer#read(CLQueue, long, long, Pointer, boolean, CLEvent[])} instead
389  * @param queue Execution queue for this operation.
390   * @param offset offset in the {@link CLBuffer}
391   * @param length length to write (in bytes)
392   * @param out output buffer
393   * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event)
394         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
395     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
396     */
397    @Deprecated
398        public CLEvent read(CLQueue queue, long offset, long length, Buffer out, boolean blocking, CLEvent... eventsToWaitFor) {
399                if (out == null)
400                        throw new IllegalArgumentException("Null output buffer !");
401                
402                if (out.isReadOnly())
403            throw new IllegalArgumentException("Output buffer for read operation is read-only !");
404        boolean indirect = !out.isDirect();
405        Pointer<T> ptr = null;
406                if (indirect) {
407                        ptr = allocateArray(io, length).order(queue.getDevice().getKernelsDefaultByteOrder());
408                        blocking = true;
409                } else {
410                        ptr = (Pointer)pointerToBuffer(out);
411        }
412        CLEvent ret = read(queue, offset, length, ptr, blocking, eventsToWaitFor);
413        if (indirect)
414            NIOUtils.put(ptr.getBuffer(), out);
415        
416        return ret;
417        }
418        
419        /**
420  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueReadBuffer.html">clEnqueueReadBuffer</a>.<br>
421  * @param queue Execution queue for this operation.
422   * @param offset offset in the {@link CLBuffer}
423   * @param length length to write (in bytes)
424   * @param out output buffer
425   * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event)
426         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
427     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
428        */
429        public CLEvent read(CLQueue queue, long offset, long length, Pointer<T> out, boolean blocking, CLEvent... eventsToWaitFor) {
430                if (out == null)
431                        throw new IllegalArgumentException("Null output pointer !");
432                
433                if (length < 0) {
434                        if (isGL) {
435                                length = out.getValidElements();
436                        }
437                        if (length < 0) {
438                                length = getElementCount();
439                                long s = out.getValidElements();
440                                if (length > s && s >= 0)
441                                        length = s;
442                        }
443                }
444                
445                                ReusablePointers ptrs = ReusablePointers.get();
446                int[] eventsInCount = ptrs.int1Array;
447        Pointer<cl_event> eventsIn = 
448                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
449                Pointer<cl_event> eventOut = 
450                blocking || eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
451                ? null 
452                : ptrs.event_out;
453        error(CL.clEnqueueReadBuffer(
454            queue.getEntity(),
455            getEntity(),
456            blocking ? CL_TRUE : 0,
457            offset * getElementSize(),
458            length * getElementSize(),
459            getPeer(out),
460              eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)          ));
461         return  CLEvent.createEventFromPointer(queue, eventOut) ;     }
462    
463        /**
464  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueWriteBuffer.html">clEnqueueWriteBuffer</a>.<br>
465     * @deprecated use {@link CLBuffer#write(CLQueue, Pointer, boolean, CLEvent[])} instead
466  * @param queue Execution queue for this operation.
467   * @param in input buffer
468   * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event)
469         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
470     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
471     */
472    @Deprecated
473        public CLEvent write(CLQueue queue, Buffer in, boolean blocking, CLEvent... eventsToWaitFor) {
474                return write(queue, 0, -1, in, blocking, eventsToWaitFor);
475        }
476        
477        /**
478  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueWriteBuffer.html">clEnqueueWriteBuffer</a>.<br>
479  * @param queue Execution queue for this operation.
480   * @param in input buffer
481   * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event)
482         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
483     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
484        */
485        public CLEvent write(CLQueue queue, Pointer<T> in, boolean blocking, CLEvent... eventsToWaitFor) {
486                return write(queue, 0, -1, in, blocking, eventsToWaitFor);
487        }
488
489        /**
490  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueWriteBuffer.html">clEnqueueWriteBuffer</a>.<br>
491     * @deprecated use {@link CLBuffer#write(CLQueue, long, long, Pointer, boolean, CLEvent[])} instead
492  * @param queue Execution queue for this operation.
493   * @param offset offset in the {@link CLBuffer}
494   * @param length length to write (in bytes)
495   * @param in input buffer
496   * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event)
497         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
498     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
499     */
500    @Deprecated
501        public CLEvent write(CLQueue queue, long offset, long length, Buffer in, boolean blocking, CLEvent... eventsToWaitFor) {
502                if (in == null)
503                        throw new IllegalArgumentException("Null input buffer !");
504                
505                boolean indirect = !in.isDirect();
506        Pointer<T> ptr = null;
507                if (indirect) {
508                        ptr = allocateArray(io, length).order(queue.getDevice().getKernelsDefaultByteOrder());
509                        ptr.setValues(in);
510                        blocking = true;
511                } else {
512                        ptr = (Pointer)pointerToBuffer(in);
513        }
514        return write(queue, offset, length, ptr, blocking, eventsToWaitFor);
515        }
516        
517        /**
518  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueWriteBuffer.html">clEnqueueWriteBuffer</a>.<br>
519  * @param queue Execution queue for this operation.
520   * @param offset offset in the {@link CLBuffer}
521   * @param length length to write (in bytes)
522   * @param in input buffer
523   * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event)
524         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
525     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
526        */
527        public CLEvent write(CLQueue queue, long offset, long length, Pointer<T> in, boolean blocking, CLEvent... eventsToWaitFor) {
528                if (length == 0)
529                        return null;
530                
531                if (in == null)
532                        throw new IllegalArgumentException("Null input pointer !");
533                
534                if (length < 0) {
535                        if (isGL)
536                                length = in.getValidElements();
537                        if (length < 0) {
538                                length = getElementCount();
539                                long s = in.getValidElements();
540                                if (length > s && s >= 0)
541                                        length = s;
542                        }
543                }
544                
545                                ReusablePointers ptrs = ReusablePointers.get();
546                int[] eventsInCount = ptrs.int1Array;
547        Pointer<cl_event> eventsIn = 
548                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
549                Pointer<cl_event> eventOut = 
550                blocking || eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
551                ? null 
552                : ptrs.event_out;
553        error(CL.clEnqueueWriteBuffer(
554            queue.getEntity(),
555            getEntity(),
556            blocking ? CL_TRUE : CL_FALSE,
557            offset * getElementSize(),
558            length * getElementSize(),
559            getPeer(in),
560              eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)          ));
561         return  CLEvent.createEventFromPointer(queue, eventOut) ;     }
562
563    /**
564  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueWriteBuffer.html">clEnqueueWriteBuffer</a>.<br>
565  * @param queue Execution queue for this operation.
566   * @param offset offset in the {@link CLBuffer}
567   * @param length length to write (in bytes)
568   * @param in input buffer
569   * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event)
570         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
571     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
572        */
573        public CLEvent writeBytes(CLQueue queue, long offset, long length, ByteBuffer in, boolean blocking, CLEvent... eventsToWaitFor) {
574                return writeBytes(queue, offset, length, pointerToBuffer(in), blocking, eventsToWaitFor);
575    }
576    /**
577  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueWriteBuffer.html">clEnqueueWriteBuffer</a>.<br>
578  * @param queue Execution queue for this operation.
579   * @param offset offset in the {@link CLBuffer}
580   * @param length length to write (in bytes)
581   * @param in input buffer
582   * @param blocking whether the operation should be blocking (and return null), or non-blocking (and return a completion event)
583         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
584     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
585        */
586        public CLEvent writeBytes(CLQueue queue, long offset, long length, Pointer<?> in, boolean blocking, CLEvent... eventsToWaitFor) {
587        if (in == null)
588                        throw new IllegalArgumentException("Null input pointer !");
589                
590                                ReusablePointers ptrs = ReusablePointers.get();
591                int[] eventsInCount = ptrs.int1Array;
592        Pointer<cl_event> eventsIn = 
593                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
594                Pointer<cl_event> eventOut = 
595                blocking || eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
596                ? null 
597                : ptrs.event_out;
598        error(CL.clEnqueueWriteBuffer(
599            queue.getEntity(),
600            getEntity(),
601            blocking ? CL_TRUE : 0,
602            offset,
603            length,
604            getPeer(in),
605              eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)          ));
606         return  CLEvent.createEventFromPointer(queue, eventOut) ;     }
607
608    private <T extends CLMem> T copyGLMark(T mem) {
609        mem.isGL = this.isGL;
610        return mem;
611    }
612        
613    public CLBuffer<T> emptyClone(CLMem.Usage usage) {
614                return (CLBuffer)getContext().createBuffer(usage, io, getElementCount());
615    }
616    
617    
618        public CLBuffer<Integer> asCLIntBuffer() {
619                return as(Integer.class);
620        }
621        
622        
623        public CLBuffer<Long> asCLLongBuffer() {
624                return as(Long.class);
625        }
626        
627        
628        public CLBuffer<Short> asCLShortBuffer() {
629                return as(Short.class);
630        }
631        
632        
633        public CLBuffer<Byte> asCLByteBuffer() {
634                return as(Byte.class);
635        }
636        
637        
638        public CLBuffer<Character> asCLCharBuffer() {
639                return as(Character.class);
640        }
641        
642        
643        public CLBuffer<Float> asCLFloatBuffer() {
644                return as(Float.class);
645        }
646        
647        
648        public CLBuffer<Double> asCLDoubleBuffer() {
649                return as(Double.class);
650        }
651        
652                
653        public <T> CLBuffer<T> as(Class<T> newTargetType) {
654                long mem = getEntity();
655                assert mem != 0;
656                error(CL.clRetainMemObject(mem));
657        PointerIO<T> newIO = PointerIO.getInstance(newTargetType);
658                return copyGLMark(new CLBuffer<T>(context, getByteCount(), mem, owner, newIO));
659        }
660
661    /**
662  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueCopyBuffer.html">clEnqueueCopyBuffer</a>.<br>
663  * @param queue Execution queue for this operation.
664    * @param destination destination buffer object
665         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
666     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
667     */
668    public CLEvent copyTo(CLQueue queue, CLBuffer destination, CLEvent... eventsToWaitFor) {
669        return copyBytesTo(queue, destination, 0, 0, getByteCount(), eventsToWaitFor);
670    }
671
672    /**
673  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueCopyBuffer.html">clEnqueueCopyBuffer</a>.<br>
674  * @param queue Execution queue for this operation.
675   * @param destination destination buffer object
676   * @param sourceByteOffset byte offset in the source
677   * @param destinationByteOffset byte offset in the destination
678   * @param byteCount number of bytes to copy
679         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
680     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
681     */
682    public CLEvent copyBytesTo(CLQueue queue, CLBuffer destination, long sourceByteOffset, long destinationByteOffset, long byteCount, CLEvent... eventsToWaitFor) {
683                        ReusablePointers ptrs = ReusablePointers.get();
684                int[] eventsInCount = ptrs.int1Array;
685        Pointer<cl_event> eventsIn = 
686                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
687                Pointer<cl_event> eventOut = 
688                eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
689                ? null 
690                : ptrs.event_out;
691        error(CL.clEnqueueCopyBuffer(
692            queue.getEntity(),
693            getEntity(),
694            destination.getEntity(),
695            sourceByteOffset,
696            destinationByteOffset,
697            byteCount,
698              eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)  ));
699                 return  CLEvent.createEventFromPointer(queue, eventOut) ;     }
700
701    /**
702  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueCopyBuffer.html">clEnqueueCopyBuffer</a>.<br>
703  * @param queue Execution queue for this operation.
704   * @param destination destination buffer object
705   * @param sourceElementOffset element offset in the source
706   * @param destinationElementOffset element offset in the destination
707   * @param elementCount number of elements to copy
708         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
709     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
710     */
711    public CLEvent copyElementsTo(CLQueue queue, CLBuffer destination, long sourceElementOffset, long destinationElementOffset, long elementCount, CLEvent... eventsToWaitFor) {
712        return copyBytesTo(queue, destination,
713            sourceElementOffset * getElementSize(),
714            destinationElementOffset * getElementSize(),
715            elementCount * getElementSize(),
716            eventsToWaitFor);
717    }
718        
719}