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        
050package com.nativelibs4java.opencl;
051import static com.nativelibs4java.opencl.CLException.error;
052import static com.nativelibs4java.opencl.JavaCL.CL;
053import static com.nativelibs4java.opencl.library.OpenCLLibrary.*;
054import static com.nativelibs4java.opencl.library.IOpenCLLibrary.*;
055
056import java.util.EnumSet;
057
058import com.nativelibs4java.opencl.library.OpenCLLibrary;
059import com.nativelibs4java.opencl.library.IOpenCLLibrary.cl_mem;
060import com.nativelibs4java.util.EnumValue;
061import com.nativelibs4java.util.EnumValues;
062import org.bridj.ann.Ptr;
063import org.bridj.*;
064import static org.bridj.Pointer.*;
065import static com.nativelibs4java.opencl.proxy.PointerUtils.*;
066
067/**
068 * OpenCL memory object.<br>
069 * Memory objects are categorized into two types: buffer objects, and image objects. <br>
070 * A buffer object stores a one-dimensional collection of elements whereas an image object is used to store a two- or three- dimensional texture, frame-buffer or image.<br>
071 * Elements of a buffer object can be a scalar data type (such as an int, float), vector data type, or a user-defined structure. An image object is used to represent a buffer that can be used as a texture or a frame-buffer. The elements of an image object are selected from a list of predefined image formats. <br>
072 * The minimum number of elements in a memory object is one.<br>
073 * The fundamental differences between a buffer and an image object are:
074 * <ul>
075 * <li>Elements in a buffer are stored in sequential fashion and can be accessed using a pointer by a kernel executing on a device. Elements of an image are stored in a format that is opaque to the user and cannot be directly accessed using a pointer. Built-in functions are provided by the OpenCL C programming language to allow a kernel to read from or write to an image.</li>
076 * <li>For a buffer object, the data is stored in the same format as it is accessed by the kernel, but in the case of an image object the data format used to store the image elements may not be the same as the data format used inside the kernel. Image elements are always a 4- component vector (each component can be a float or signed/unsigned integer) in a kernel. The built-in function to read from an image converts image element from the format it is stored into a 4-component vector. Similarly, the built-in function to write to an image converts the image element from a 4-component vector to the appropriate image format specified such as 4 8-bit elements, for example.</li>
077 * </ul>
078 *
079 * Kernels take memory objects as input, and output to one or more memory objects.
080 * @author Olivier Chafik
081 */
082public abstract class CLMem extends CLAbstractEntity {
083
084    protected final CLContext context;
085    protected long byteCount = -1;
086    boolean isGL;
087
088        protected static CLInfoGetter infos = new CLInfoGetter() {
089                @Override
090                protected int getInfo(long entity, int infoTypeEnum, long size, Pointer out, Pointer<SizeT> sizeOut) {
091                        return CL.clGetImageInfo(entity, infoTypeEnum, size, getPeer(out), getPeer(sizeOut));
092                }
093        };
094
095    CLMem(CLContext context, long byteCount, long entityPeer) {
096        super(entityPeer);
097        this.byteCount = byteCount;
098        this.context = context;
099    }
100        
101    public CLContext getContext() {
102        return context;
103    }
104
105    public interface DestructorCallback {
106        void callback(CLMem mem);
107    }
108    
109    /**
110  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clSetMemObjectDestructorCallback.html">clSetMemObjectDestructorCallback</a>.<br>
111     * Registers a user callback function that will be called when the memory object is deleted and its resources freed. <br>
112     * Each call to clSetMemObjectDestructorCallback registers the specified user callback function on a callback stack associated with memobj. <br>
113     * The registered user callback functions are called in the reverse order in which they were registered. <br>
114     * The user callback functions are called and then the memory object's resources are freed and the memory object is deleted. <br>
115     * This provides a mechanism for the application (and libraries) using memobj to be notified when the memory referenced by host_ptr, specified when the memory object is created and used as the storage bits for the memory object, can be reused or freed.
116     * @since OpenCL 1.1
117     * @param callback
118     */
119    public void setDestructorCallback(final DestructorCallback callback) {
120                context.getPlatform().requireMinVersionValue("clSetMemObjectDestructorCallback", 1.1);
121        clSetMemObjectDestructorCallback_arg1_callback cb = new clSetMemObjectDestructorCallback_arg1_callback() {
122                @Override
123                public void apply(@Ptr long mem, @Ptr long userData) {
124                        callback.callback(CLMem.this);
125                }
126        };
127        BridJ.protectFromGC(cb);
128        error(CL.clSetMemObjectDestructorCallback(getEntity(), getPeer(getPointer(cb)), 0));
129    }
130    
131    public CLEvent acquireGLObject(CLQueue queue, CLEvent... eventsToWaitFor) {
132        return queue.enqueueAcquireGLObjects(new CLMem[] { this }, eventsToWaitFor);
133    }
134
135    public CLEvent releaseGLObject(CLQueue queue, CLEvent... eventsToWaitFor) {
136        return queue.enqueueReleaseGLObjects(new CLMem[] { this }, eventsToWaitFor);
137    }
138
139    /**
140     * Get the actual size of the memory object in bytes
141     * @return actual size of the memory object in bytes
142     */
143    public long getByteCount() {
144        if (byteCount < 0) {
145            try {
146                byteCount = infos.getIntOrLong(getEntity(), CL_MEM_SIZE);
147            } catch (CLException.InvalidMemObject ex) {
148                if (isGL)
149                    return -1; // GL objects are not (always?) considered as valid mem objects
150                else
151                    throw ex;
152            }
153        }
154        return byteCount;
155    }
156
157        /**
158         * Memory Object Usage enum
159         */
160        public enum Usage {
161                Input(CL_MEM_READ_ONLY, Flags.ReadOnly),
162                Output(CL_MEM_WRITE_ONLY, Flags.WriteOnly),
163                InputOutput(CL_MEM_READ_WRITE, Flags.ReadWrite);
164
165                private int intFlags;
166                private Flags flags;
167                Usage(int intFlags, Flags flags) {
168                        this.intFlags = intFlags;
169                        this.flags = flags;
170                }
171                public int getIntFlags() {
172                        return intFlags;
173                }
174                public Flags getFlags() {
175                        return flags;
176                }
177        }
178
179        /**
180         * Memory object migration options (see {@link CLQueue#enqueueMigrateMemObjects(CLMem[], java.lang.EnumSet, CLEvent[])}).
181         */
182        public enum Migration implements com.nativelibs4java.util.ValuedEnum {
183                /**
184                 * This flag indicates that the specified set of memory objects are to be migrated 
185                 * to the host, regardless of the target command-queue.
186                 */
187                Host(CL_MIGRATE_MEM_OBJECT_HOST),
188                /**
189                 * This flag indicates that the contents of the set of memory objects are undefined after 
190                 * migration. The specified set of memory objects are migrated to the device associated with 
191                 * command_queue without incurring the overhead of migrating their contents.
192                 */
193                ContentUndefined(CL_MIGRATE_MEM_OBJECT_CONTENT_UNDEFINED);
194
195        Migration(long value) { this.value = value; }
196        long value;
197        @Override
198        public long value() { return value; }
199        public static long getValue(EnumSet<Migration> set) {
200            return EnumValues.getValue(set);
201        }
202
203        public static EnumSet<Migration> getEnumSet(long v) {
204            return EnumValues.getEnumSet(v, Migration.class);
205        }
206    }
207
208        public enum Flags implements com.nativelibs4java.util.ValuedEnum {
209                /**
210                 * This flag specifies that the memory object will be read and written by a kernel. This is the default.
211                 */
212                ReadWrite(CL_MEM_READ_WRITE),
213                /**
214                 * This flags specifies that the memory object will be written but not read by a kernel.<br>
215                 * Reading from a buffer or image object created with CL_MEM_WRITE_ONLY inside a kernel is undefined.
216                 */
217                WriteOnly(CL_MEM_WRITE_ONLY),
218                /**
219                 * This flag specifies that the memory object is a read-only memory object when used inside a kernel. <br>
220                 * Writing to a buffer or image object created with CL_MEM_READ_ONLY inside a kernel is undefined.
221                 */
222                ReadOnly(CL_MEM_READ_ONLY),
223                /**
224                 * This flag is valid only if host_ptr is not NULL. If specified, it indicates that the application wants the OpenCL implementation to use memory referenced by host_ptr as the storage bits for the memory object. <br>
225                 * OpenCL implementations are allowed to cache the buffer contents pointed to by host_ptr in device memory. This cached copy can be used when kernels are executed on a device. <br>
226                 * The result of OpenCL commands that operate on multiple buffer objects created with the same host_ptr or overlapping host regions is considered to be undefined.
227                 */
228                UseHostPtr(CL_MEM_USE_HOST_PTR),
229                /**
230                 * This flag specifies that the application wants the OpenCL implementation to allocate memory from host accessible memory. <br>
231                 * CL_MEM_ALLOC_HOST_PTR and CL_MEM_USE_HOST_PTR are mutually exclusive.<br>
232                 * CL_MEM_COPY_HOST_PTR: This flag is valid only if host_ptr is not NULL. If specified, it indicates that the application wants the OpenCL implementation to allocate memory for the memory object and copy the data from memory referenced by host_ptr.<br>
233                 * CL_MEM_COPY_HOST_PTR and CL_MEM_USE_HOST_PTR are mutually exclusive.<br>
234                 * CL_MEM_COPY_HOST_PTR can be used with CL_MEM_ALLOC_HOST_PTR to initialize the contents of the cl_mem object allocated using host-accessible (e.g. PCIe) memory.
235                 */
236                AllocHostPtr(CL_MEM_ALLOC_HOST_PTR),
237                CopyHostPtr(CL_MEM_COPY_HOST_PTR);
238
239                Flags(long value) { this.value = value; }
240                long value;
241                @Override
242                public long value() { return value; }
243                public static long getValue(EnumSet<Flags> set) { return EnumValues.getValue(set); }
244                public static EnumSet<Flags> getEnumSet(long v) { return EnumValues.getEnumSet(v, Flags.class); }
245        }
246        public enum ObjectType implements com.nativelibs4java.util.ValuedEnum {
247                Buffer(CL_MEM_OBJECT_BUFFER),
248                Image2D(CL_MEM_OBJECT_IMAGE2D),
249                Image3D(CL_MEM_OBJECT_IMAGE3D);
250
251                ObjectType(long value) { this.value = value; }
252                long value;
253                @Override
254                public long value() { return value; }
255                public static ObjectType getEnum(long v) { return EnumValues.getEnum(v, ObjectType.class); }
256        }
257
258    public enum GLObjectType implements com.nativelibs4java.util.ValuedEnum {
259                Buffer(CL_GL_OBJECT_BUFFER),
260                RenderBuffer(CL_GL_OBJECT_RENDERBUFFER),
261                Texture2D(CL_GL_OBJECT_TEXTURE2D),
262                Texture3D(CL_GL_OBJECT_TEXTURE3D);
263
264                GLObjectType(long value) { this.value = value; }
265                long value;
266                @Override
267                public long value() { return value; }
268                public static GLObjectType getEnum(long v) { return EnumValues.getEnum(v, GLObjectType.class); }
269        }
270
271    public static class GLObjectInfo {
272        final GLObjectType type;
273        final int name;
274        public GLObjectInfo(GLObjectType type, int name) {
275            this.type = type;
276            this.name = name;
277        }
278        public GLObjectType getType() {
279            return type;
280        }
281        public int getName() {
282            return name;
283        }
284    }
285    /**
286  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clGetGLObjectInfo.html">clGetGLObjectInfo</a>.<br>
287     */
288    @SuppressWarnings("deprecation")
289        public GLObjectInfo getGLObjectInfo() {
290                        ReusablePointers ptrs = ReusablePointers.get();
291        Pointer<Integer> typeRef = ptrs.int1;
292        Pointer<Integer> nameRef = ptrs.int2;
293        CL.clGetGLObjectInfo(getEntity(), getPeer(typeRef), getPeer(nameRef));
294        return new GLObjectInfo(GLObjectType.getEnum(typeRef.getInt()), nameRef.getInt());
295    }
296        public enum MapFlags implements com.nativelibs4java.util.ValuedEnum {
297                Read(CL_MAP_READ),
298                Write(CL_MAP_WRITE),
299                ReadWrite(CL_MAP_READ | CL_MAP_WRITE),
300        WriteInvalidateRegion(CL_MAP_WRITE_INVALIDATE_REGION);
301
302                MapFlags(long value) { this.value = value; }
303                long value;
304                public long value() { return value; }
305                public static MapFlags getEnum(long v) { return EnumValues.getEnum(v, MapFlags.class); }
306        }
307
308    @Override
309    protected void clear() {
310        error(CL.clReleaseMemObject(getEntity()));
311    }
312}