Переглянути джерело

reworked releasing system.

Now one has to either release a native OpenCLObject manually with release() or register it for automatic garbage collection using register().
These changes greatly improve the performance by reducing the load on the OpenCLObjectManager.
shamanDevel 9 роки тому
батько
коміт
4be6013068
27 змінених файлів з 230 додано та 155 видалено
  1. 62 0
      jme3-core/src/main/java/com/jme3/opencl/AbstractOpenCLObject.java
  2. 5 1
      jme3-core/src/main/java/com/jme3/opencl/Buffer.java
  3. 7 3
      jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java
  4. 5 1
      jme3-core/src/main/java/com/jme3/opencl/Context.java
  5. 11 5
      jme3-core/src/main/java/com/jme3/opencl/Event.java
  6. 28 24
      jme3-core/src/main/java/com/jme3/opencl/Image.java
  7. 3 2
      jme3-core/src/main/java/com/jme3/opencl/Kernel.java
  8. 32 2
      jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java
  9. 4 3
      jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java
  10. 12 6
      jme3-core/src/main/java/com/jme3/opencl/Program.java
  11. 18 1
      jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java
  12. 7 3
      jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java
  13. 8 3
      jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java
  14. 1 5
      jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java
  15. 4 10
      jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclCommandQueue.java
  16. 1 7
      jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java
  17. 4 7
      jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclEvent.java
  18. 2 6
      jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java
  19. 1 5
      jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java
  20. 2 11
      jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java
  21. 1 5
      jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java
  22. 2 6
      jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java
  23. 1 5
      jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java
  24. 4 16
      jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java
  25. 2 6
      jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java
  26. 1 1
      jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java
  27. 2 11
      jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java

+ 62 - 0
jme3-core/src/main/java/com/jme3/opencl/AbstractOpenCLObject.java

@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009-2016 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER 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.
+ */
+package com.jme3.opencl;
+
+/**
+ * Abstract implementation of {@link OpenCLObject} providing the release 
+ * mechanisms.
+ * @author Sebastian Weiss
+ */
+public abstract class AbstractOpenCLObject implements OpenCLObject {
+    
+    protected final ObjectReleaser releaser;
+    protected AbstractOpenCLObject(ObjectReleaser releaser) {
+        this.releaser = releaser;
+    }
+    @Override
+    public void register() {
+        OpenCLObjectManager.getInstance().registerObject(this);
+    }
+    @Override
+    public void release() {
+        releaser.release();
+    }
+    @Override
+    @SuppressWarnings("FinalizeDeclaration")
+    protected void finalize() throws Throwable {
+        release();
+    }
+    @Override
+    public ObjectReleaser getReleaser() {
+        return releaser;
+    }
+}

+ 5 - 1
jme3-core/src/main/java/com/jme3/opencl/Buffer.java

@@ -47,8 +47,12 @@ import java.nio.ByteBuffer;
  * @see Context#createBuffer(long, com.jme3.opencl.MemoryAccess) 
  * @author shaman
  */
-public abstract class Buffer implements OpenCLObject {
+public abstract class Buffer extends AbstractOpenCLObject {
 
+    protected Buffer(ObjectReleaser releaser) {
+        super(releaser);
+    }
+    
     /**
      * @return the size of the buffer in bytes.
      * @see Context#createBuffer(long) 

+ 7 - 3
jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java

@@ -42,8 +42,12 @@ package com.jme3.opencl;
  * and all commands are sent to this device.
  * @author shaman
  */
-public interface CommandQueue extends OpenCLObject {
+public abstract class CommandQueue extends AbstractOpenCLObject {
 
+    protected CommandQueue(ObjectReleaser releaser) {
+        super(releaser);
+    }
+    
     /**
      * Issues all previously queued OpenCL commands in command_queue to the
      * device associated with command queue. Flush only guarantees that all
@@ -51,7 +55,7 @@ public interface CommandQueue extends OpenCLObject {
      * appropriate device. There is no guarantee that they will be complete
      * after flush returns.
      */
-    void flush();
+    public abstract void flush();
 
     /**
      * Blocks until all previously queued OpenCL commands in command queue are
@@ -59,6 +63,6 @@ public interface CommandQueue extends OpenCLObject {
      * return until all previously queued commands in command queue have been
      * processed and completed. Finish is also a synchronization point.
      */
-    void finish();
+    public abstract void finish();
 
 }

+ 5 - 1
jme3-core/src/main/java/com/jme3/opencl/Context.java

@@ -63,9 +63,13 @@ import java.util.logging.Logger;
  * </ul>
  * @author shaman
  */
-public abstract class Context implements OpenCLObject {
+public abstract class Context extends AbstractOpenCLObject {
     private static final Logger LOG = Logger.getLogger(Context.class.getName());
 
+    protected Context(ObjectReleaser releaser) {
+        super(releaser);
+    }
+
     /**
      * Returns all available devices for this context.
      * These devices all belong to the same {@link Platform}.

+ 11 - 5
jme3-core/src/main/java/com/jme3/opencl/Event.java

@@ -38,16 +38,22 @@ package com.jme3.opencl;
  * is done.
  * @author shaman
  */
-public interface Event extends OpenCLObject {
+public abstract class Event extends AbstractOpenCLObject {
+
+    protected Event(ObjectReleaser releaser) {
+        super(releaser);
+    }
 	
     /**
-     * Waits until the action has finished (blocking)
+     * Waits until the action has finished (blocking).
+     * This automatically releases the event.
      */
-	void waitForFinished();
+	public abstract void waitForFinished();
 	
     /**
-     * Tests if the action is completed
+     * Tests if the action is completed.
+     * If the action is completed, the event is released.
      * @return {@code true} if the action is completed
      */
-	boolean isCompleted();
+	public abstract boolean isCompleted();
 }

+ 28 - 24
jme3-core/src/main/java/com/jme3/opencl/Image.java

@@ -74,7 +74,7 @@ import java.util.Objects;
  *
  * @author shaman
  */
-public interface Image extends OpenCLObject {
+public abstract class Image extends AbstractOpenCLObject {
     
     /**
      * {@code ImageChannelType} describes the size of the channel data type.
@@ -245,47 +245,51 @@ memory layout in which channels are stored in the image.
         }
         
     }
+
+    protected Image(ObjectReleaser releaser) {
+        super(releaser);
+    }
     
     /**
      * @return the width of the image
      */
-    long getWidth();
+    public abstract long getWidth();
     /**
      * @return the height of the image
      */
-    long getHeight();
+    public abstract long getHeight();
     /**
      * @return the depth of the image
      */
-    long getDepth();
+    public abstract long getDepth();
     /**
      * @return the row pitch when the image was created from a host buffer
      * @see ImageDescriptor#ImageDescriptor(com.jme3.opencl.Image.ImageType, long, long, long, long, long, long, java.nio.ByteBuffer) 
      */
-    long getRowPitch();
+    public abstract long getRowPitch();
     /**
      * @return the slice pitch when the image was created from a host buffer
      * @see ImageDescriptor#ImageDescriptor(com.jme3.opencl.Image.ImageType, long, long, long, long, long, long, java.nio.ByteBuffer) 
      */
-    long getSlicePitch();
+    public abstract long getSlicePitch();
     /**
      * @return the number of elements in the image array
      * @see ImageType#IMAGE_1D_ARRAY
      * @see ImageType#IMAGE_2D_ARRAY
      */
-    long getArraySize();
+    public abstract long getArraySize();
     /**
      * @return the image format
      */
-    ImageFormat getImageFormat();
+    public abstract ImageFormat getImageFormat();
     /**
      * @return the image type
      */
-    ImageType getImageType();
+    public abstract ImageType getImageType();
     /**
      * @return the number of bytes per pixel
      */
-    int getElementSize();
+    public abstract int getElementSize();
     
     /**
      * Performs a blocking read of the image into the specified byte buffer.
@@ -298,7 +302,7 @@ memory layout in which channels are stored in the image.
      * @param slicePitch the slice pitch of the target buffer, must be set to 0 for 1D and 2D images.
      * If set to 0 for 3D images, the slice pitch is calculated as {@code rowPitch * height}
      */
-    void readImage(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch);
+    public abstract void readImage(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch);
     /**
      * Performs an async/non-blocking read of the image into the specified byte buffer.
      * @param queue the command queue
@@ -311,7 +315,7 @@ memory layout in which channels are stored in the image.
      * If set to 0 for 3D images, the slice pitch is calculated as {@code rowPitch * height}
      * @return the event object indicating the status of the operation
      */
-    Event readImageAsync(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch);
+    public abstract Event readImageAsync(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch);
     
     /**
      * Performs a blocking write from the specified byte buffer into the image.
@@ -324,7 +328,7 @@ memory layout in which channels are stored in the image.
      * @param slicePitch the slice pitch of the target buffer, must be set to 0 for 1D and 2D images.
      * If set to 0 for 3D images, the slice pitch is calculated as {@code rowPitch * height}
      */
-    void writeImage(CommandQueue queue, ByteBuffer src, long[] origin, long[] region, long rowPitch, long slicePitch);
+    public abstract void writeImage(CommandQueue queue, ByteBuffer src, long[] origin, long[] region, long rowPitch, long slicePitch);
     /**
      * Performs an async/non-blocking write from the specified byte buffer into the image.
      * @param queue the command queue
@@ -337,7 +341,7 @@ memory layout in which channels are stored in the image.
      * If set to 0 for 3D images, the slice pitch is calculated as {@code rowPitch * height}
      * @return the event object indicating the status of the operation
      */
-    Event writeImageAsync(CommandQueue queue, ByteBuffer src, long[] origin, long[] region, long rowPitch, long slicePitch);
+    public abstract Event writeImageAsync(CommandQueue queue, ByteBuffer src, long[] origin, long[] region, long rowPitch, long slicePitch);
     
     /**
      * Performs a blocking copy operation from one image to another.
@@ -348,7 +352,7 @@ memory layout in which channels are stored in the image.
      * @param destOrigin the target image origin, see class description for the format
      * @param region the copied region, see class description for the format
      */
-    void copyTo(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region);
+    public abstract void copyTo(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region);
     /**
      * Performs an async/non-blocking copy operation from one image to another.
      * <b>Important:</b> Both images must have the same format!
@@ -359,7 +363,7 @@ memory layout in which channels are stored in the image.
      * @param region the copied region, see class description for the format
      * @return the event object indicating the status of the operation
      */
-    Event copyToAsync(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region);
+    public abstract Event copyToAsync(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region);
     
     /**
      * Maps the image into host memory.
@@ -373,7 +377,7 @@ memory layout in which channels are stored in the image.
      * @return a structure describing the mapped memory
      * @see #unmap(com.jme3.opencl.CommandQueue, com.jme3.opencl.Image.ImageMapping) 
      */
-    ImageMapping map(CommandQueue queue, long[] origin, long[] region, MappingAccess access);
+    public abstract ImageMapping map(CommandQueue queue, long[] origin, long[] region, MappingAccess access);
     /**
      * Non-blocking version of {@link #map(com.jme3.opencl.CommandQueue, long[], long[], com.jme3.opencl.MappingAccess) }.
      * The returned structure contains the mapped byte buffer and row and slice pitch.
@@ -385,13 +389,13 @@ memory layout in which channels are stored in the image.
      * @return a structure describing the mapped memory
      * @see #unmap(com.jme3.opencl.CommandQueue, com.jme3.opencl.Image.ImageMapping) 
      */
-    ImageMapping mapAsync(CommandQueue queue, long[] origin, long[] region, MappingAccess access);
+    public abstract ImageMapping mapAsync(CommandQueue queue, long[] origin, long[] region, MappingAccess access);
     /**
      * Unmaps the mapped memory
      * @param queue the command queue
      * @param mapping the mapped memory
      */
-    void unmap(CommandQueue queue, ImageMapping mapping);
+    public abstract void unmap(CommandQueue queue, ImageMapping mapping);
     
     /**
      * Describes a mapped region of the image
@@ -442,7 +446,7 @@ memory layout in which channels are stored in the image.
      * @param color the color to fill
      * @return an event object to detect for the completion
      */
-    Event fillAsync(CommandQueue queue, long[] origin, long[] region, ColorRGBA color);
+    public abstract Event fillAsync(CommandQueue queue, long[] origin, long[] region, ColorRGBA color);
     /**
      * Fills the image with the specified color given as four integer variables.
      * Does <b>not</b> work if the image channel is {@link ImageChannelType#FLOAT}
@@ -453,7 +457,7 @@ memory layout in which channels are stored in the image.
      * @param color the color to fill, must be an array of length 4
      * @return an event object to detect for the completion
      */
-    Event fillAsync(CommandQueue queue, long[] origin, long[] region, int[] color);
+    public abstract Event fillAsync(CommandQueue queue, long[] origin, long[] region, int[] color);
     
     /**
      * Copies this image into the specified buffer, no format conversion is done.
@@ -466,7 +470,7 @@ memory layout in which channels are stored in the image.
      * @param destOffset an offset into the target buffer
      * @return the event object to detect the completion of the operation
      */
-    Event copyToBufferAsync(CommandQueue queue, Buffer dest, long[] srcOrigin, long[] srcRegion, long destOffset);
+    public abstract Event copyToBufferAsync(CommandQueue queue, Buffer dest, long[] srcOrigin, long[] srcRegion, long destOffset);
     
     /**
      * Aquires this image object for using. Only call this method if this image
@@ -480,7 +484,7 @@ memory layout in which channels are stored in the image.
      * @param queue the command queue
      * @return the event object
      */
-    Event acquireImageForSharingAsync(CommandQueue queue);
+    public abstract Event acquireImageForSharingAsync(CommandQueue queue);
     /**
      * Releases a shared image object.
      * Call this method after the image object was acquired by
@@ -489,7 +493,7 @@ memory layout in which channels are stored in the image.
      * @param queue the command queue
      * @return the event object
      */
-    Event releaseImageForSharingAsync(CommandQueue queue);
+    public abstract Event releaseImageForSharingAsync(CommandQueue queue);
     
     //TODO: add variants of the above two methods that don't create the event object, but release the event immediately
 }

+ 3 - 2
jme3-core/src/main/java/com/jme3/opencl/Kernel.java

@@ -82,7 +82,7 @@ import java.util.Arrays;
  * @author shaman
  * @see Program#createKernel(java.lang.String) 
  */
-public abstract class Kernel implements OpenCLObject {
+public abstract class Kernel extends AbstractOpenCLObject {
     /**
      * The current global work size
      */
@@ -92,7 +92,8 @@ public abstract class Kernel implements OpenCLObject {
      */
     protected final WorkSize workGroupSize;
 
-    protected Kernel() {
+    protected Kernel(ObjectReleaser releaser) {
+        super(releaser);
         this.globalWorkSize = new WorkSize(0);
         this.workGroupSize = new WorkSize(0);
     }

+ 32 - 2
jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java

@@ -32,14 +32,44 @@
 package com.jme3.opencl;
 
 /**
- * 
+ * Base interface of all native OpenCL objects.
+ * This interface provides the functionality for savely release the object.
  * @author shaman
  */
 public interface OpenCLObject {
     
+    /**
+     * Releaser for an {@link OpenCLObject}.
+     * Implementations of this interface must not hold a reference to the
+     * {@code OpenCLObject} directly.
+     */
     public static interface ObjectReleaser {
+        /**
+         * Releases the native resources of the associated {@link OpenCLObject}.
+         * This method must be guarded against multiple calls: only the first
+         * call should release, the next ones must not throw an exception.
+         */
         void release();
     }
+    /**
+     * Returns the releaser object. Multiple calls should return the same object.
+     * The ObjectReleaser is used to release the OpenCLObject when it is garbage
+     * collected. Therefore, the returned object must not hold a reference to
+     * the OpenCLObject.
+     * @return the object releaser
+     */
     ObjectReleaser getReleaser();
-
+    /**
+     * Releases this native object.
+     * Should delegate to {@code getReleaser().release()}.
+     */
+    void release();
+    /**
+     * Registers this object for automatic releasing on garbage collection.
+     * By default, OpenCLObjects are not registered in the
+     * {@link OpenCLObjectManager}, you have to release it manually 
+     * by calling {@link #release() }.
+     * Without registering or releasing, a memory leak might occur.
+     */
+    void register();
 }

+ 4 - 3
jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java

@@ -43,8 +43,8 @@ import java.util.logging.Logger;
  */
 public class OpenCLObjectManager {
     private static final Logger LOG = Logger.getLogger(OpenCLObjectManager.class.getName());
-    private static final Level LOG_LEVEL1 = Level.FINER;
-    private static final Level LOG_LEVEL2 = Level.FINE;
+    private static final Level LOG_LEVEL1 = Level.INFO;
+    private static final Level LOG_LEVEL2 = Level.INFO;
     /**
      * Call Runtime.getRuntime().gc() every these frames
      */
@@ -85,6 +85,7 @@ public class OpenCLObjectManager {
         
     public void deleteUnusedObjects() {
         if (activeObjects.isEmpty()) {
+            LOG.log(LOG_LEVEL2, "no active natives");
             return; //nothing to do
         }
         
@@ -108,7 +109,7 @@ public class OpenCLObjectManager {
             removed++;
         }
         if (removed >= 1) {
-            LOG.log(LOG_LEVEL2, "NativeObjectManager: {0} native objects were removed from native", removed);
+            LOG.log(LOG_LEVEL2, "{0} native objects were removed from native", removed);
         }
     }
     

+ 12 - 6
jme3-core/src/main/java/com/jme3/opencl/Program.java

@@ -42,8 +42,12 @@ package com.jme3.opencl;
  * @see #createKernel(java.lang.String) 
  * @author shaman
  */
-public interface Program extends OpenCLObject {
-	
+public abstract class Program extends AbstractOpenCLObject {
+
+    protected Program(ObjectReleaser releaser) {
+        super(releaser);
+    }
+    
     /**
      * Builds this program with the specified argument string.
      * Please see the official OpenCL specification for a definition of
@@ -52,13 +56,15 @@ public interface Program extends OpenCLObject {
      * @throws KernelCompilationException if the compilation fails
      * @see #build() 
      */
-	void build(String args) throws KernelCompilationException;
+	public abstract void build(String args) throws KernelCompilationException;
     /**
      * Builds this program without additional arguments
      * @throws KernelCompilationException if the compilation fails
      * @see #build(java.lang.String) 
      */
-	void build() throws KernelCompilationException;
+	public void build() throws KernelCompilationException {
+        build("");
+    }
 
     /**
      * Creates the kernel with the specified name.
@@ -67,13 +73,13 @@ public interface Program extends OpenCLObject {
      * @throws OpenCLException if the kernel was not found or some other
      * error occured
      */
-	Kernel createKernel(String name);
+	public abstract Kernel createKernel(String name);
     
     /**
      * Creates all available kernels in this program.
      * The names of the kernels can then by queried by {@link Kernel#getName() }.
      * @return an array of all kernels
      */
-	Kernel[] createAllKernels();
+	public abstract Kernel[] createAllKernels();
     
 }

+ 18 - 1
jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java

@@ -85,6 +85,8 @@ public class HelloOpenCL extends SimpleApplication {
         str.append("\n  Kernel: ").append(testKernel(clContext, clQueue));
         str.append("\n  Images: ").append(testImages(clContext, clQueue));
         
+        clQueue.release();
+        
         BitmapText txt1 = new BitmapText(fnt);
         txt1.setText(str.toString());
         txt1.setLocalTranslation(5, settings.getHeight() - 5, 0);
@@ -159,6 +161,10 @@ public class HelloOpenCL extends SimpleApplication {
                 assertEquals((byte) (i+low), b, "Wrong byte read");
             }
         
+            //release
+            b1.release();
+            b2.release();
+            
         } catch (AssertionError ex) {
             LOG.log(Level.SEVERE, "Buffer test failed with an assertion error");
             return false;
@@ -193,6 +199,11 @@ public class HelloOpenCL extends SimpleApplication {
                 assertEquals(value, v, "Buffer filled with the wrong value at index "+i);
             }
             buffer.unmap(clQueue, buf);
+            
+            //release
+            buffer.release();
+            kernel.release();
+            program.release();
 
         } catch (AssertionError ex) {
             LOG.log(Level.SEVERE, "kernel test failed with an assertion error");
@@ -239,7 +250,8 @@ public class HelloOpenCL extends SimpleApplication {
             
             //copy to a buffer
             Buffer buffer = clContext.createBuffer(4*4*500*1024);
-            image.copyToBufferAsync(clQueue, buffer, new long[]{10,10,0}, new long[]{500,1024,1}, 0);
+            Event e3 = image.copyToBufferAsync(clQueue, buffer, new long[]{10,10,0}, new long[]{500,1024,1}, 0);
+            e3.release();
             //this buffer must be completely red
             ByteBuffer map1 = buffer.map(clQueue, MappingAccess.MAP_READ_ONLY);
             FloatBuffer map1F = map1.asFloatBuffer(); map1F.rewind();
@@ -282,6 +294,11 @@ public class HelloOpenCL extends SimpleApplication {
             }
             image2.unmap(clQueue, map2);
             
+            //release
+            image.release();
+            image2.release();
+            buffer.release();
+            
         } catch (AssertionError ex) {
             LOG.log(Level.SEVERE, "image test failed with an assertion error");
             return false;

+ 7 - 3
jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java

@@ -107,6 +107,7 @@ public class TestVertexBufferSharing extends SimpleApplication {
     private void initOpenCL1() {
         clContext = context.getOpenCLContext();
         clQueue = clContext.createQueue();
+        clQueue.register();
         //create kernel
         String source = ""
                 + "__kernel void ScaleKernel(__global float* vb, float scale)\n"
@@ -118,12 +119,15 @@ public class TestVertexBufferSharing extends SimpleApplication {
                 + "}\n";
         Program program = clContext.createProgramFromSourceCode(source);
         program.build();
+        program.register();
         kernel = program.createKernel("ScaleKernel");
+        kernel.register();
     }
     private void initOpenCL2() {
         //bind vertex buffer to OpenCL
         VertexBuffer vb = geom.getMesh().getBuffer(VertexBuffer.Type.Position);
         buffer = clContext.bindVertexBuffer(vb, MemoryAccess.READ_WRITE);
+        buffer.register();
         ws = new com.jme3.opencl.Kernel.WorkSize(geom.getMesh().getVertexCount());
     }
     private void updateOpenCL(float tpf) {
@@ -131,15 +135,15 @@ public class TestVertexBufferSharing extends SimpleApplication {
         time += tpf;
         
         //aquire resource
-        buffer.acquireBufferForSharingAsync(clQueue);
+        buffer.acquireBufferForSharingAsync(clQueue).release();
         //no need to wait for the returned event, since the kernel implicitely waits for it (same command queue)
         
         //execute kernel
         float scale = (float) Math.pow(1.1, (1.0 - time%2) / 16.0);
-        kernel.Run1(clQueue, ws, buffer, scale);
+        kernel.Run1(clQueue, ws, buffer, scale).release();
         
         //release resource
-        buffer.releaseBufferForSharingAsync(clQueue);
+        buffer.releaseBufferForSharingAsync(clQueue).release();
     }
 
 }

+ 8 - 3
jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java

@@ -120,26 +120,31 @@ public class TestWriteToTexture extends SimpleApplication implements AnalogListe
     private void initOpenCL1() {
         clContext = context.getOpenCLContext();
         clQueue = clContext.createQueue();
+        clQueue.register();
         //create kernel
         Program program = clContext.createProgramFromSourceFiles(assetManager, "jme3test/opencl/JuliaSet.cl");
         program.build();
+        program.register();
         kernel = program.createKernel("JuliaSet");
+        kernel.register();
         C = new Vector2f(0.12f, -0.2f);
     }
     private void initOpenCL2() {
         //bind image to OpenCL
         texCL = clContext.bindImage(tex, MemoryAccess.WRITE_ONLY);
+        texCL.register();
     }
     private void updateOpenCL(float tpf) {
         //aquire resource
-        texCL.acquireImageForSharingAsync(clQueue);
+        texCL.acquireImageForSharingAsync(clQueue).release();
         //no need to wait for the returned event, since the kernel implicitely waits for it (same command queue)
         
         //execute kernel
-        kernel.Run1(clQueue, new com.jme3.opencl.Kernel.WorkSize(settings.getWidth(), settings.getHeight()), texCL, C, 16);
+        kernel.Run1(clQueue, new com.jme3.opencl.Kernel.WorkSize(settings.getWidth(), settings.getHeight()), texCL, C, 16)
+                .release();
         
         //release resource
-        texCL.releaseImageForSharingAsync(clQueue);
+        texCL.releaseImageForSharingAsync(clQueue).release();
     }
 
     @Override

+ 1 - 5
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java

@@ -48,9 +48,9 @@ public class JoclBuffer extends Buffer {
     final CL cl;
 
     public JoclBuffer(long id) {
+        super(new ReleaserImpl(id));
         this.id = id;
         this.cl = CLPlatform.getLowLevelCLInterface();
-        OpenCLObjectManager.getInstance().registerObject(this);
     }
     
     @Override
@@ -203,10 +203,6 @@ public class JoclBuffer extends Buffer {
         return new JoclEvent(event);
     }
 
-    @Override
-    public ObjectReleaser getReleaser() {
-        return new ReleaserImpl(id);
-    }
     private static class ReleaserImpl implements ObjectReleaser {
         private long mem;
         private ReleaserImpl(long mem) {

+ 4 - 10
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclCommandQueue.java

@@ -42,15 +42,15 @@ import com.jogamp.opencl.llb.CLCommandQueueBinding;
  *
  * @author shaman
  */
-public class JoclCommandQueue implements CommandQueue {
+public class JoclCommandQueue extends CommandQueue {
 
     final CL cl;
     final long id;
 
     public JoclCommandQueue(long id) {
+        super(new ReleaserImpl(id));
         this.id = id;
         this.cl = CLPlatform.getLowLevelCLInterface();
-        OpenCLObjectManager.getInstance().registerObject(this);
     }
     
     @Override
@@ -65,23 +65,17 @@ public class JoclCommandQueue implements CommandQueue {
         Utils.checkError(ret, "clFinish");
     }
     
-    @Override
-    public ObjectReleaser getReleaser() {
-        return new ReleaserImpl(id, cl);
-    }
     private static class ReleaserImpl implements ObjectReleaser {
         private long id;
-        private CLCommandQueueBinding cl;
 
-        private ReleaserImpl(long id, CLCommandQueueBinding cl) {
+        private ReleaserImpl(long id) {
             this.id = id;
-            this.cl = cl;
         }
         
         @Override
         public void release() {
             if (id != 0) {
-                int ret = cl.clReleaseCommandQueue(id);
+                int ret = CLPlatform.getLowLevelCLInterface().clReleaseCommandQueue(id);
                 id = 0;
                 Utils.reportError(ret, "clReleaseCommandQueue");
             }

+ 1 - 7
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java

@@ -40,7 +40,6 @@ import com.jme3.texture.FrameBuffer;
 import com.jme3.texture.Texture;
 import com.jogamp.opencl.CLContext;
 import com.jogamp.opencl.CLImageFormat;
-import com.jogamp.opencl.CLMemory;
 import com.jogamp.opencl.CLMemory.Mem;
 import com.jogamp.opencl.CLPlatform;
 import com.jogamp.opencl.llb.CL;
@@ -48,7 +47,6 @@ import com.jogamp.opencl.llb.gl.CLGL;
 import com.jogamp.opencl.llb.impl.CLImageFormatImpl;
 import com.jogamp.opengl.GL;
 import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -66,11 +64,11 @@ public class JoclContext extends Context {
     private final List<JoclDevice> devices;
 
     public JoclContext(CLContext context, List<JoclDevice> devices) {
+        super(new ReleaserImpl(context.ID, devices));
         this.context = context;
         this.id = context.ID;
         this.cl = context.getCL();
         this.devices = devices;
-        OpenCLObjectManager.getInstance().registerObject(this);
     }
 
     public CLContext getContext() {
@@ -224,10 +222,6 @@ public class JoclContext extends Context {
         return new JoclProgram(p, this);
     }
 
-    @Override
-    public ObjectReleaser getReleaser() {
-        return new ReleaserImpl(id, devices);
-    }
     private static class ReleaserImpl implements ObjectReleaser {
         private long id;
         private final List<JoclDevice> devices;

+ 4 - 7
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclEvent.java

@@ -41,16 +41,16 @@ import java.util.logging.Logger;
  *
  * @author shaman
  */
-public class JoclEvent implements Event {
+public class JoclEvent extends Event {
     private static final Logger LOG = Logger.getLogger(JoclEvent.class.getName());
     
     final long id;
     final CL cl;
 
     public JoclEvent(long id) {
+        super(new ReleaserImpl(id));
         this.id = id;
         this.cl = CLPlatform.getLowLevelCLInterface();
-        OpenCLObjectManager.getInstance().registerObject(this);
     }
 
     @Override
@@ -59,6 +59,7 @@ public class JoclEvent implements Event {
         Utils.pointers[0].put(0, id);
         int ret = cl.clWaitForEvents(1, Utils.pointers[0]);
         Utils.checkError(ret, "clWaitForEvents");
+        release();
     }
 
     @Override
@@ -68,6 +69,7 @@ public class JoclEvent implements Event {
         Utils.checkError(err, "clGetEventInfo");
         int status = Utils.tempBuffers[0].b16i.get(0);
         if (status == CL.CL_SUCCESS) {
+            release();
             return true;
         } else if (status < 0) {
             Utils.checkError(status, "EventStatus");
@@ -76,11 +78,6 @@ public class JoclEvent implements Event {
             return false;
         }
     }
-
-    @Override
-    public ObjectReleaser getReleaser() {
-        return new ReleaserImpl(id);
-    }
     
     private static class ReleaserImpl implements ObjectReleaser {
         private long event;

+ 2 - 6
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java

@@ -44,16 +44,16 @@ import java.util.logging.Logger;
  *
  * @author shaman
  */
-public class JoclImage implements Image {
+public class JoclImage extends Image {
     private static final Logger LOG = Logger.getLogger(JoclImage.class.getName());
 
     final long id;
     final CL cl;
 
     public JoclImage(long image) {
+        super(new ReleaserImpl(image));
         this.id = image;
         this.cl = CLPlatform.getLowLevelCLInterface();
-        OpenCLObjectManager.getInstance().registerObject(this);
     }
 
     public static int decodeImageChannelOrder(ImageChannelOrder order) {
@@ -512,10 +512,6 @@ public class JoclImage implements Image {
         return new JoclEvent(event);
     }
     
-    @Override
-    public ObjectReleaser getReleaser() {
-        return new ReleaserImpl(id);
-    }
     private static class ReleaserImpl implements ObjectReleaser {
         private long mem;
         private ReleaserImpl(long mem) {

+ 1 - 5
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java

@@ -37,7 +37,6 @@ import com.jme3.math.Vector4f;
 import com.jme3.opencl.*;
 import com.jme3.opencl.Buffer;
 import com.jogamp.common.nio.PointerBuffer;
-import com.jogamp.opencl.CLKernel;
 import com.jogamp.opencl.CLPlatform;
 import com.jogamp.opencl.llb.CL;
 import java.nio.*;
@@ -55,6 +54,7 @@ public class JoclKernel extends Kernel {
     final CL cl;
 
     public JoclKernel(long kernel) {
+        super(new ReleaserImpl(kernel));
         this.kernel = kernel;
         this.cl = CLPlatform.getLowLevelCLInterface();
         OpenCLObjectManager.getInstance().registerObject(this);
@@ -240,10 +240,6 @@ public class JoclKernel extends Kernel {
         return new JoclEvent(Utils.pointers[0].get(0));
     }
 
-    @Override
-    public ObjectReleaser getReleaser() {
-        return new ReleaserImpl(kernel);
-    }
     private static class ReleaserImpl implements ObjectReleaser {
         private long kernel;
         private ReleaserImpl(long kernel) {

+ 2 - 11
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java

@@ -50,7 +50,7 @@ import static com.jogamp.opencl.llb.CL.CL_SUCCESS;
  *
  * @author shaman
  */
-public class JoclProgram implements Program {
+public class JoclProgram extends Program {
     private static final Logger LOG = Logger.getLogger(JoclProgram.class.getName());
     
     final long program;
@@ -58,10 +58,10 @@ public class JoclProgram implements Program {
     private final JoclContext context;
 
     public JoclProgram(long program, JoclContext context) {
+        super(new ReleaserImpl(program));
         this.program = program;
         this.context = context;
         this.cl = CLPlatform.getLowLevelCLInterface();
-        OpenCLObjectManager.getInstance().registerObject(this);
     }
 
     @Override
@@ -79,11 +79,6 @@ public class JoclProgram implements Program {
             LOG.log(Level.INFO, "Program compiled:\n{0}", Log());
         }
     }
-
-    @Override
-    public void build() throws KernelCompilationException {
-        build("");
-    }
     
     private String Log(long device) {
         Utils.pointers[0].rewind();
@@ -131,10 +126,6 @@ public class JoclProgram implements Program {
         return kx;
     }
 
-    @Override
-    public ObjectReleaser getReleaser() {
-        return new ReleaserImpl(program);
-    }
     private static class ReleaserImpl implements ObjectReleaser {
         private long program;
         private ReleaserImpl(long program) {

+ 1 - 5
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java

@@ -44,8 +44,8 @@ public class LwjglBuffer extends Buffer {
     private final CLMem buffer;
 
     public LwjglBuffer(CLMem buffer) {
+        super(new ReleaserImpl(buffer));
         this.buffer = buffer;
-        OpenCLObjectManager.getInstance().registerObject(this);
     }
     public CLMem getBuffer() {
         return buffer;
@@ -205,10 +205,6 @@ public class LwjglBuffer extends Buffer {
         return new LwjglEvent(q.getCLEvent(event));
     }
 
-    @Override
-    public ObjectReleaser getReleaser() {
-        return new ReleaserImpl(buffer);
-    }
     private static class ReleaserImpl implements ObjectReleaser {
         private CLMem mem;
         private ReleaserImpl(CLMem mem) {

+ 2 - 6
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java

@@ -40,13 +40,13 @@ import org.lwjgl.opencl.CLCommandQueue;
  *
  * @author shaman
  */
-public class LwjglCommandQueue implements CommandQueue {
+public class LwjglCommandQueue extends CommandQueue {
 
     private final CLCommandQueue queue;
 
     public LwjglCommandQueue(CLCommandQueue queue) {
+        super(new ReleaserImpl(queue));
         this.queue = queue;
-        OpenCLObjectManager.getInstance().registerObject(this);
     }
     
     public CLCommandQueue getQueue() {
@@ -65,10 +65,6 @@ public class LwjglCommandQueue implements CommandQueue {
         Utils.checkError(ret, "clFinish");
     }
     
-    @Override
-    public ObjectReleaser getReleaser() {
-        return new ReleaserImpl(queue);
-    }
     private static class ReleaserImpl implements ObjectReleaser {
         private CLCommandQueue queue;
         private ReleaserImpl(CLCommandQueue queue) {

+ 1 - 5
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java

@@ -57,9 +57,9 @@ public class LwjglContext extends Context {
     private final List<LwjglDevice> devices;
 
     public LwjglContext(CLContext context, List<LwjglDevice> devices) {
+        super(new ReleaserImpl(context, devices));
         this.context = context;
         this.devices = devices;
-        OpenCLObjectManager.getInstance().registerObject(this);
     }
 
     public CLContext getContext() {
@@ -208,10 +208,6 @@ public class LwjglContext extends Context {
         return new LwjglProgram(p, this);
     }
 
-    @Override
-    public ObjectReleaser getReleaser() {
-        return new ReleaserImpl(context, devices);
-    }
     private static class ReleaserImpl implements ObjectReleaser {
         private CLContext context;
         private final List<LwjglDevice> devices;

+ 4 - 16
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java

@@ -41,31 +41,24 @@ import org.lwjgl.opencl.CLEvent;
  *
  * @author shaman
  */
-public class LwjglEvent implements Event {
+public class LwjglEvent extends Event {
     private static final Logger LOG = Logger.getLogger(LwjglEvent.class.getName());
     private CLEvent event;
+    private ReleaserImpl releaser;
 
     public LwjglEvent(CLEvent event) {
+        super(new ReleaserImpl(event));
         this.event = event;
         if (event == null) {
             LOG.warning("event is null!");
         } else {
-            OpenCLObjectManager.getInstance().registerObject(this);
+            this.releaser = new ReleaserImpl(event);
         }
     }
 
     public CLEvent getEvent() {
         return event;
     }
-    
-    protected void release() {
-        if (event != null && event.isValid()) {
-            int ret = CL10.clReleaseEvent(event);
-            event = null;
-            Utils.reportError(ret, "clReleaseEvent");
-            LOG.finer("Event deleted");
-        }
-    }
 
     @Override
     public void waitForFinished() {
@@ -93,11 +86,6 @@ public class LwjglEvent implements Event {
         }
     }
 
-    @Override
-    public ObjectReleaser getReleaser() {
-        return new ReleaserImpl(event);
-    }
-    
     private static class ReleaserImpl implements ObjectReleaser {
         private CLEvent event;
 

+ 2 - 6
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java

@@ -43,14 +43,14 @@ import org.lwjgl.opencl.api.CLImageFormat;
  *
  * @author shaman
  */
-public class LwjglImage implements Image {
+public class LwjglImage extends Image {
     private static final Logger LOG = Logger.getLogger(LwjglImage.class.getName());
 
     private final CLMem image;
 
     public LwjglImage(CLMem image) {
+        super(new ReleaserImpl(image));
         this.image = image;
-        OpenCLObjectManager.getInstance().registerObject(this);
     }
 
     public CLMem getImage() {
@@ -543,10 +543,6 @@ public class LwjglImage implements Image {
         return new LwjglEvent(q.getCLEvent(event));
     }
     
-    @Override
-    public ObjectReleaser getReleaser() {
-        return new ReleaserImpl(image);
-    }
     private static class ReleaserImpl implements ObjectReleaser {
         private CLMem mem;
         private ReleaserImpl(CLMem mem) {

+ 1 - 1
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java

@@ -52,8 +52,8 @@ public class LwjglKernel extends Kernel {
     private final CLKernel kernel;
 
     public LwjglKernel(CLKernel kernel) {
+        super(new ReleaserImpl(kernel));
         this.kernel = kernel;
-        OpenCLObjectManager.getInstance().registerObject(this);
     }
 
     public CLKernel getKernel() {

+ 2 - 11
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java

@@ -44,16 +44,16 @@ import org.lwjgl.opencl.*;
  *
  * @author shaman
  */
-public class LwjglProgram implements Program {
+public class LwjglProgram extends Program {
     private static final Logger LOG = Logger.getLogger(LwjglProgram.class.getName());
     
     private final CLProgram program;
     private final LwjglContext context;
 
     public LwjglProgram(CLProgram program, LwjglContext context) {
+        super(new ReleaserImpl(program));
         this.program = program;
         this.context = context;
-        OpenCLObjectManager.getInstance().registerObject(this);
     }
 
     public CLProgram getProgram() {
@@ -75,11 +75,6 @@ public class LwjglProgram implements Program {
             LOG.log(Level.INFO, "Program compiled:\n{0}", Log());
         }
     }
-
-    @Override
-    public void build() throws KernelCompilationException {
-        build("");
-    }
     
     private String Log() {
         StringBuilder str = new StringBuilder();
@@ -109,10 +104,6 @@ public class LwjglProgram implements Program {
         return kx;
     }
 
-    @Override
-    public ObjectReleaser getReleaser() {
-        return new ReleaserImpl(program);
-    }
     private static class ReleaserImpl implements ObjectReleaser {
         private CLProgram program;
         private ReleaserImpl(CLProgram program) {