All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jogamp.opencl.CLMemory Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2009 JogAmp Community. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are
 * permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice, this list of
 *       conditions and the following disclaimer.
 *
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list
 *       of conditions and the following disclaimer in the documentation and/or other materials
 *       provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation are those of the
 * authors and should not be interpreted as representing official policies, either expressed
 * or implied, of JogAmp Community.
 */

package com.jogamp.opencl;

import com.jogamp.opencl.llb.CLMemObjBinding;
import com.jogamp.common.nio.Buffers;
import com.jogamp.common.nio.PointerBuffer;
import com.jogamp.opencl.llb.CL;
import com.jogamp.opencl.llb.impl.CLMemObjectDestructorCallback;
import java.nio.Buffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;

import static com.jogamp.opencl.CLException.*;
import static com.jogamp.opencl.llb.gl.CLGL.*;

/**
 * Common superclass for all OpenCL memory types.
 * Represents an OpenCL memory object and wraps an optional NIO buffer.
 * @author Michael Bien, et al.
 */
public abstract class CLMemory  extends CLObjectResource {

    B buffer;
    protected final int FLAGS;
    protected long size;

    // depends on the nio buffer type
    protected int elementSize;
    protected int clCapacity;

    private final CLMemObjBinding binding;

    protected  CLMemory(final CLContext context, final long size, final long id, final int flags) {
        this(context, null, size, id, flags);
    }

    protected CLMemory(final CLContext context, final B directBuffer, final long size, final long id, final int flags) {
        super(context, id);
        this.buffer = directBuffer;
        this.FLAGS = flags;
        this.size = size;
        this.binding = context.getPlatform().getMemObjectBinding();
        initElementSize();
        initCLCapacity();
    }

    private void initElementSize() {
        this.elementSize = (buffer==null) ? 1 : Buffers.sizeOfBufferElem(buffer);
    }

    protected final void initCLCapacity() {
        this.clCapacity  = (int) (size / elementSize);
    }

    /**
     * Returns true if a host pointer must be specified on mem object creation.
     */
    protected static boolean isHostPointerFlag(final int flags) {
        return (flags & CL_MEM_COPY_HOST_PTR) != 0
            || (flags & CL_MEM_USE_HOST_PTR)  != 0;
    }

    protected static long getSizeImpl(final CLContext context, final long id) {
        final PointerBuffer pb = PointerBuffer.allocateDirect(1);
        final CLMemObjBinding binding = context.getPlatform().getMemObjectBinding(); // FIXME: CL separation makes this pretty complicated !
        final int ret = binding.clGetMemObjectInfo(id, CL_MEM_SIZE, pb.elementSize(), pb.getBuffer(), null);
        checkForError(ret, "can not obtain buffer info");
        return pb.get();
    }

    protected static CL getCL(final CLContext context) {
        return context.getCL();
    }

    /**
     * Registers a callback which will be called by the OpenCL implementation
     * when the memory object is released.
     */
    public void registerDestructorCallback(final CLMemObjectListener listener) {
        binding.clSetMemObjectDestructorCallback(ID, new CLMemObjectDestructorCallback() {
            @Override
            public void memoryDeallocated(final long memObjID) {
                listener.memoryDeallocated(CLMemory.this);
            }
        });
    }

    /**
     * Returns a new instance of CLMemory pointing to the same CLResource but using a different Buffer.
     */
    public abstract  CLMemory cloneWith(T directBuffer);


    public CLMemory use(final B buffer) {
        if(this.buffer != null && buffer != null && this.buffer.getClass() != buffer.getClass()) {
            throw new IllegalArgumentException(
                    "expected a Buffer of class " + this.buffer.getClass()
                    +" but got " + buffer.getClass());
        }
        this.buffer = buffer;
        initElementSize();
        initCLCapacity();
        return this;
    }

    /**
     * Returns the optional NIO buffer for this memory object.
     */
    public B getBuffer() {
        return buffer;
    }

    /**
     * Returns the capacity of the wrapped direct buffer or 0 if no buffer available.
     */
    public int getNIOCapacity() {
        if(buffer == null) {
            return 0;
        }
        return buffer.capacity();
    }

    /**
     * Returns the size of the wrapped direct buffer in byte or 0 if no buffer available.
     */
    public int getNIOSize() {
        if(buffer == null) {
            return 0;
        }
        return getElementSize() * buffer.capacity();
    }

    /**
     * Returns the size of the allocated OpenCL memory in bytes.
     */
    public long getCLSize() {
        return size;
    }

    /**
     * Returns the size in buffer elements of this memory object.
     */
    public int getCLCapacity() {
        return clCapacity;
    }

    /**
     * Returns the size in bytes of a single buffer element.
     * This method returns 1 if no buffer is available indicating regular byte access.
     */
    public int getElementSize() {
        return elementSize;
    }

    /**
     * Returns the configuration of this memory object.
     */
    public EnumSet getConfig() {
        return Mem.valuesOf(FLAGS);
    }

    /**
     * Returns the number of buffer mappings. The map count returned should be considered immediately stale.
     * It is unsuitable for general use in applications. This feature is provided for debugging.
     */
    public int getMapCount() {
        final IntBuffer value = Buffers.newDirectIntBuffer(1);
        final int ret = binding.clGetMemObjectInfo(ID, CL_MEM_MAP_COUNT, 4, value, null);
        checkForError(ret, "can not obtain buffer map count.");
        return value.get();
    }

    /**
     * Returns true if this memory object was created with the {@link Mem#READ_ONLY} flag.
     */
    public boolean isReadOnly() {
        return (Mem.READ_ONLY.CONFIG & FLAGS) != 0;
    }

    /**
     * Returns true if this memory object was created with the {@link Mem#WRITE_ONLY} flag.
     */
    public boolean isWriteOnly() {
        return (Mem.WRITE_ONLY.CONFIG & FLAGS) != 0;
    }

    /**
     * Returns true if this memory object was created with the {@link Mem#READ_WRITE} flag.
     */
    public boolean isReadWrite() {
        return (Mem.READ_WRITE.CONFIG & FLAGS) != 0;
    }

    @Override
    public void release() {
        super.release();
        final int ret = binding.clReleaseMemObject(ID);
        context.onMemoryReleased(this);
        if(ret != CL_SUCCESS) {
            throw newException(ret, "can not release "+this);
        }
    }

    // TODO kept only temporary for debugging purposes
    /**
     * Returns the OpenGL buffer type of this shared buffer.
     */
//    @Deprecated
//    /*public*/ final GLObjectType _getGLObjectType() {
//        int[] array = new int[1];
//        int ret = ((CLGL)cl).clGetGLObjectInfo(ID, array, 0, null, 0);
//        CLException.checkForError(ret, "error while asking for gl object info");
//        return GLObjectType.valueOf(array[0]);
//    }
//
//    /**
//     * Returns the OpenGL object id of this shared buffer.
//     */
//    @Deprecated
//    /*public*/ final int _getGLObjectID() {
//        int[] array = new int[1];
//        int ret = ((CLGL)cl).clGetGLObjectInfo(ID, null, 0, array, 0);
//        CLException.checkForError(ret, "error while asking for gl object info");
//        return array[0];
//    }

    @Override
    public boolean equals(final Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final CLMemory other = (CLMemory) obj;
        if (this.ID != other.ID) {
            return false;
        }
        if (this.context != other.context && (this.context == null || !this.context.equals(other.context))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 83 * hash + (int) (this.ID ^ (this.ID >>> 32));
        hash = 83 * hash + (this.context != null ? this.context.hashCode() : 0);
        return hash;
    }

    @Override
    public String toString() {
        return getClass().getSimpleName()+" [id: " + ID+" buffer: "+buffer+"]";
    }

    /**
     * Memory settings for configuring CLMemory.
     */
    public enum Mem {

        /**
         * Enum representing CL_MEM_READ_WRITE.
         * This flag specifies that the memory object will be read and
         * written by a kernel.
         */
        READ_WRITE(CL_MEM_READ_WRITE),

        /**
         * Enum representing CL_MEM_WRITE_ONLY.
         * This flags specifies that the memory object will be written
         * but not read by a kernel.
         * Reading from a buffer or image object created with WRITE_ONLY
         * inside a kernel is undefined.
         */
        WRITE_ONLY(CL_MEM_WRITE_ONLY),

        /**
         * Enum representing CL_MEM_READ_ONLY.
         * This flag specifies that the memory object is a read-only memory
         * object when used inside a kernel. Writing to a buffer or image object
         * created withREAD_ONLY inside a kernel is undefined.
         */
        READ_ONLY(CL_MEM_READ_ONLY),

        /**
         * Enum representing CL_MEM_USE_HOST_PTR.
         * 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. 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.
         */
        USE_BUFFER(CL_MEM_USE_HOST_PTR),

        /**
         * Enum representing CL_MEM_ALLOC_HOST_PTR.
         * This flag specifies that the application wants the OpenCL implementation
         * to allocate memory from host accessible memory.
         * {@link #ALLOCATE_BUFFER} and {@link #USE_BUFFER} are mutually exclusive.
         */
        ALLOCATE_BUFFER(CL_MEM_ALLOC_HOST_PTR),

        /**
         * Enum representing CL_MEM_COPY_HOST_PTR.
         * If {@link #COPY_BUFFER} 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.
* {@link #COPY_BUFFER} and {@link #USE_BUFFER} are mutually exclusive. */ COPY_BUFFER(CL_MEM_COPY_HOST_PTR); /** * Value of wrapped OpenCL flag. */ public final int CONFIG; private Mem(final int config) { this.CONFIG = config; } public static Mem valueOf(final int bufferFlag) { switch (bufferFlag) { case CL_MEM_READ_WRITE: return Mem.READ_WRITE; case CL_MEM_READ_ONLY: return Mem.READ_ONLY; case CL_MEM_WRITE_ONLY: return Mem.WRITE_ONLY; case CL_MEM_USE_HOST_PTR: return Mem.USE_BUFFER; case(CL_MEM_ALLOC_HOST_PTR): return ALLOCATE_BUFFER; case CL_MEM_COPY_HOST_PTR: return Mem.COPY_BUFFER; } return null; } public static EnumSet valuesOf(final int bitfield) { final List matching = new ArrayList(); final Mem[] values = Mem.values(); for (final Mem value : values) { if((value.CONFIG & bitfield) != 0) matching.add(value); } if(matching.isEmpty()) return EnumSet.noneOf(Mem.class); else return EnumSet.copyOf(matching); } public static int flagsToInt(final Mem[] flags) { int clFlags = 0; if (flags != null) { for (int i = 0; i < flags.length; i++) { clFlags |= flags[i].CONFIG; } } if (clFlags == 0) { clFlags = CL_MEM_READ_WRITE; } return clFlags; } } /** * Configures the mapping process. * @see com.jogamp.opencl.CLCommandQueue#putMapBuffer(CLBuffer, com.jogamp.opencl.CLMemory.Map, boolean). * @see com.jogamp.opencl.CLCommandQueue#putMapImage(CLImage2d, com.jogamp.opencl.CLMemory.Map, boolean) * @see com.jogamp.opencl.CLCommandQueue#putMapImage(CLImage3d, com.jogamp.opencl.CLMemory.Map, boolean) */ public enum Map { /** * Enum representing CL_MAP_READ | CL_MAP_WRITE. * This flag specifies that the memory object will be mapped for read and write operation. */ READ_WRITE(CL_MAP_READ | CL_MAP_WRITE), /** * Enum representing CL_MAP_WRITE. * This flag specifies that the memory object will be mapped for write operation. */ WRITE(CL_MAP_WRITE), /** * Enum representing CL_MAP_READ. * This flag specifies that the memory object will be mapped for read operation. */ READ(CL_MAP_READ); /** * Value of wrapped OpenCL flag. */ public final int FLAGS; private Map(final int flags) { this.FLAGS = flags; } public Map valueOf(final int flag) { if(flag == WRITE.FLAGS) return WRITE; else if(flag == READ.FLAGS) return READ; else if(flag == READ_WRITE.FLAGS) return READ_WRITE; return null; } } public enum GLObjectType { GL_OBJECT_BUFFER(CL_GL_OBJECT_BUFFER), GL_OBJECT_TEXTURE2D(CL_GL_OBJECT_TEXTURE2D), GL_OBJECT_TEXTURE3D(CL_GL_OBJECT_TEXTURE3D), GL_OBJECT_RENDERBUFFER(CL_GL_OBJECT_RENDERBUFFER); public final int TYPE; private GLObjectType(final int type) { this.TYPE = type; } public static GLObjectType valueOf(final int type) { if(type == CL_GL_OBJECT_BUFFER) return GL_OBJECT_BUFFER; else if(type == CL_GL_OBJECT_TEXTURE2D) return GL_OBJECT_TEXTURE2D; else if(type == CL_GL_OBJECT_TEXTURE3D) return GL_OBJECT_TEXTURE3D; else if(type == CL_GL_OBJECT_RENDERBUFFER) return GL_OBJECT_RENDERBUFFER; return null; } } }