commit
fbf2dd4497
@ -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; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,427 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
import java.nio.ByteBuffer; |
||||||
|
|
||||||
|
/** |
||||||
|
* Wrapper for an OpenCL buffer object. |
||||||
|
* A buffer object stores a one-dimensional collection of elements. 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> |
||||||
|
* Buffers are created by the {@link Context}. |
||||||
|
* <br> |
||||||
|
* All access methods (read/write/copy/map) are available in both sychronized/blocking versions |
||||||
|
* and in async/non-blocking versions. The later ones always return an {@link Event} object |
||||||
|
* and have the prefix -Async in their name. |
||||||
|
* |
||||||
|
* @see Context#createBuffer(long, com.jme3.opencl.MemoryAccess) |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public abstract class Buffer extends AbstractOpenCLObject { |
||||||
|
|
||||||
|
protected Buffer(ObjectReleaser releaser) { |
||||||
|
super(releaser); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the size of the buffer in bytes. |
||||||
|
* @see Context#createBuffer(long) |
||||||
|
*/ |
||||||
|
public abstract long getSize(); |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the memory access flags set on creation. |
||||||
|
* @see Context#createBuffer(long, com.jme3.opencl.MemoryAccess) |
||||||
|
*/ |
||||||
|
public abstract MemoryAccess getMemoryAccessFlags(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs a blocking read of the buffer. |
||||||
|
* The target buffer must have at least {@code size} bytes remaining. |
||||||
|
* This method may set the limit to the last byte read. |
||||||
|
* @param queue the command queue |
||||||
|
* @param dest the target buffer |
||||||
|
* @param size the size in bytes being read |
||||||
|
* @param offset the offset in bytes in the buffer to read from |
||||||
|
*/ |
||||||
|
public abstract void read(CommandQueue queue, ByteBuffer dest, long size, long offset); |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #read(com.jme3.opencl.CommandQueue, java.nio.ByteBuffer, long, long) }, |
||||||
|
* sets {@code offset} to zero. |
||||||
|
*/ |
||||||
|
public void read(CommandQueue queue, ByteBuffer dest, long size) { |
||||||
|
read(queue, dest, size, 0); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #read(com.jme3.opencl.CommandQueue, java.nio.ByteBuffer, long) }, |
||||||
|
* sets {@code size} to {@link #getSize() }. |
||||||
|
*/ |
||||||
|
public void read(CommandQueue queue, ByteBuffer dest) { |
||||||
|
read(queue, dest, getSize()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs an async/non-blocking read of the buffer. |
||||||
|
* The target buffer must have at least {@code size} bytes remaining. |
||||||
|
* This method may set the limit to the last byte read. |
||||||
|
* @param queue the command queue |
||||||
|
* @param dest the target buffer |
||||||
|
* @param size the size in bytes being read |
||||||
|
* @param offset the offset in bytes in the buffer to read from |
||||||
|
* @return the event indicating when the memory has been fully read into the provided buffer |
||||||
|
*/ |
||||||
|
public abstract Event readAsync(CommandQueue queue, ByteBuffer dest, long size, long offset); |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #readAsync(com.jme3.opencl.CommandQueue, java.nio.ByteBuffer, long, long) }, |
||||||
|
* sets {@code offset} to zero. |
||||||
|
*/ |
||||||
|
public Event readAsync(CommandQueue queue, ByteBuffer dest, long size) { |
||||||
|
return readAsync(queue, dest, size, 0); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #readAsync(com.jme3.opencl.CommandQueue, java.nio.ByteBuffer, long) }, |
||||||
|
* sets {@code size} to {@link #getSize() } |
||||||
|
*/ |
||||||
|
public Event readAsync(CommandQueue queue, ByteBuffer dest) { |
||||||
|
return readAsync(queue, dest, getSize()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs a blocking write to the buffer. |
||||||
|
* The target buffer must have at least {@code size} bytes remaining. |
||||||
|
* This method may set the limit to the last byte that will be written. |
||||||
|
* @param queue the command queue |
||||||
|
* @param src the source buffer, its data is written to this buffer |
||||||
|
* @param size the size in bytes to write |
||||||
|
* @param offset the offset into the target buffer |
||||||
|
*/ |
||||||
|
public abstract void write(CommandQueue queue, ByteBuffer src, long size, long offset); |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #write(com.jme3.opencl.CommandQueue, java.nio.ByteBuffer, long, long) }, |
||||||
|
* sets {@code offset} to zero. |
||||||
|
*/ |
||||||
|
public void write(CommandQueue queue, ByteBuffer src, long size) { |
||||||
|
write(queue, src, size, 0); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #write(com.jme3.opencl.CommandQueue, java.nio.ByteBuffer, long) }, |
||||||
|
* sets {@code size} to {@link #getSize() }. |
||||||
|
*/ |
||||||
|
public void write(CommandQueue queue, ByteBuffer src) { |
||||||
|
write(queue, src, getSize()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs an async/non-blocking write to the buffer. |
||||||
|
* The target buffer must have at least {@code size} bytes remaining. |
||||||
|
* This method may set the limit to the last byte that will be written. |
||||||
|
* @param queue the command queue |
||||||
|
* @param src the source buffer, its data is written to this buffer |
||||||
|
* @param size the size in bytes to write |
||||||
|
* @param offset the offset into the target buffer |
||||||
|
* @return the event object indicating when the write operation is completed |
||||||
|
*/ |
||||||
|
public abstract Event writeAsync(CommandQueue queue, ByteBuffer src, long size, long offset); |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #writeAsync(com.jme3.opencl.CommandQueue, java.nio.ByteBuffer, long, long) }, |
||||||
|
* sets {@code offset} to zero. |
||||||
|
*/ |
||||||
|
public Event writeAsync(CommandQueue queue, ByteBuffer src, long size) { |
||||||
|
return writeAsync(queue, src, size, 0); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #writeAsync(com.jme3.opencl.CommandQueue, java.nio.ByteBuffer, long) }, |
||||||
|
* sets {@code size} to {@link #getSize() }. |
||||||
|
*/ |
||||||
|
public Event writeAsync(CommandQueue queue, ByteBuffer src) { |
||||||
|
return writeAsync(queue, src, getSize()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs a blocking copy operation from this buffer to the specified buffer. |
||||||
|
* @param queue the command queue |
||||||
|
* @param dest the target buffer |
||||||
|
* @param size the size in bytes to copy |
||||||
|
* @param srcOffset offset in bytes into this buffer |
||||||
|
* @param destOffset offset in bytes into the target buffer |
||||||
|
*/ |
||||||
|
public abstract void copyTo(CommandQueue queue, Buffer dest, long size, long srcOffset, long destOffset); |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #copyTo(com.jme3.opencl.CommandQueue, com.jme3.opencl.Buffer, long, long, long) }, |
||||||
|
* sets {@code srcOffset} and {@code destOffset} to zero. |
||||||
|
*/ |
||||||
|
public void copyTo(CommandQueue queue, Buffer dest, long size) { |
||||||
|
copyTo(queue, dest, size, 0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #copyTo(com.jme3.opencl.CommandQueue, com.jme3.opencl.Buffer, long) }, |
||||||
|
* sets {@code size} to {@code this.getSize()}. |
||||||
|
*/ |
||||||
|
public void copyTo(CommandQueue queue, Buffer dest) { |
||||||
|
copyTo(queue, dest, getSize()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs an async/non-blocking copy operation from this buffer to the specified buffer. |
||||||
|
* @param queue the command queue |
||||||
|
* @param dest the target buffer |
||||||
|
* @param size the size in bytes to copy |
||||||
|
* @param srcOffset offset in bytes into this buffer |
||||||
|
* @param destOffset offset in bytes into the target buffer |
||||||
|
* @return the event object indicating when the copy operation is finished |
||||||
|
*/ |
||||||
|
public abstract Event copyToAsync(CommandQueue queue, Buffer dest, long size, long srcOffset, long destOffset); |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #copyToAsync(com.jme3.opencl.CommandQueue, com.jme3.opencl.Buffer, long, long, long) }, |
||||||
|
* sets {@code srcOffset} and {@code destOffset} to zero. |
||||||
|
*/ |
||||||
|
public Event copyToAsync(CommandQueue queue, Buffer dest, long size) { |
||||||
|
return copyToAsync(queue, dest, size, 0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #copyToAsync(com.jme3.opencl.CommandQueue, com.jme3.opencl.Buffer, long) }, |
||||||
|
* sets {@code size} to {@code this.getSize()}. |
||||||
|
*/ |
||||||
|
public Event copyToAsync(CommandQueue queue, Buffer dest) { |
||||||
|
return copyToAsync(queue, dest, getSize()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Maps this buffer directly into host memory. This might be the fastest method |
||||||
|
* to access the contents of the buffer since the OpenCL implementation directly |
||||||
|
* provides the memory.<br> |
||||||
|
* <b>Important:</b> The mapped memory MUST be released by calling |
||||||
|
* {@link #unmap(com.jme3.opencl.CommandQueue, java.nio.ByteBuffer) }. |
||||||
|
* @param queue the command queue |
||||||
|
* @param size the size in bytes to map |
||||||
|
* @param offset the offset into this buffer |
||||||
|
* @param access specifies the possible access to the memory: READ_ONLY, WRITE_ONLY, READ_WRITE |
||||||
|
* @return the byte buffer directly reflecting the buffer contents |
||||||
|
*/ |
||||||
|
public abstract ByteBuffer map(CommandQueue queue, long size, long offset, MappingAccess access); |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #map(com.jme3.opencl.CommandQueue, long, long, com.jme3.opencl.MappingAccess) }, |
||||||
|
* sets {@code offset} to zero. |
||||||
|
* <b>Important:</b> The mapped memory MUST be released by calling |
||||||
|
* {@link #unmap(com.jme3.opencl.CommandQueue, java.nio.ByteBuffer) }. |
||||||
|
*/ |
||||||
|
public ByteBuffer map(CommandQueue queue, long size, MappingAccess access) { |
||||||
|
return map(queue, size, 0, access); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #map(com.jme3.opencl.CommandQueue, long, com.jme3.opencl.MappingAccess) }, |
||||||
|
* sets {@code size} to {@link #getSize() }. |
||||||
|
* <b>Important:</b> The mapped memory MUST be released by calling |
||||||
|
* {@link #unmap(com.jme3.opencl.CommandQueue, java.nio.ByteBuffer) }. |
||||||
|
*/ |
||||||
|
public ByteBuffer map(CommandQueue queue, MappingAccess access) { |
||||||
|
return map(queue, getSize(), access); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Unmaps a previously mapped memory. |
||||||
|
* This releases the native resources and for WRITE_ONLY or READ_WRITE access, |
||||||
|
* the memory content is sent back to the GPU. |
||||||
|
* @param queue the command queue |
||||||
|
* @param ptr the buffer that was previously mapped |
||||||
|
*/ |
||||||
|
public abstract void unmap(CommandQueue queue, ByteBuffer ptr); |
||||||
|
|
||||||
|
/** |
||||||
|
* Maps this buffer asynchronously into host memory. This might be the fastest method |
||||||
|
* to access the contents of the buffer since the OpenCL implementation directly |
||||||
|
* provides the memory.<br> |
||||||
|
* <b>Important:</b> The mapped memory MUST be released by calling |
||||||
|
* {@link #unmap(com.jme3.opencl.CommandQueue, java.nio.ByteBuffer) }. |
||||||
|
* @param queue the command queue |
||||||
|
* @param size the size in bytes to map |
||||||
|
* @param offset the offset into this buffer |
||||||
|
* @param access specifies the possible access to the memory: READ_ONLY, WRITE_ONLY, READ_WRITE |
||||||
|
* @return the byte buffer directly reflecting the buffer contents |
||||||
|
* and the event indicating when the buffer contents are available |
||||||
|
*/ |
||||||
|
public abstract AsyncMapping mapAsync(CommandQueue queue, long size, long offset, MappingAccess access); |
||||||
|
/** |
||||||
|
* Alternative version of {@link #mapAsync(com.jme3.opencl.CommandQueue, long, long, com.jme3.opencl.MappingAccess) }, |
||||||
|
* sets {@code offset} to zero. |
||||||
|
* <b>Important:</b> The mapped memory MUST be released by calling |
||||||
|
* {@link #unmap(com.jme3.opencl.CommandQueue, java.nio.ByteBuffer) }. |
||||||
|
*/ |
||||||
|
public AsyncMapping mapAsync(CommandQueue queue, long size, MappingAccess access) { |
||||||
|
return mapAsync(queue, size, 0, access); |
||||||
|
} |
||||||
|
/** |
||||||
|
* Alternative version of {@link #mapAsync(com.jme3.opencl.CommandQueue, long, com.jme3.opencl.MappingAccess) }, |
||||||
|
* sets {@code size} to {@link #getSize() }. |
||||||
|
* <b>Important:</b> The mapped memory MUST be released by calling |
||||||
|
* {@link #unmap(com.jme3.opencl.CommandQueue, java.nio.ByteBuffer) }. |
||||||
|
*/ |
||||||
|
public AsyncMapping mapAsync(CommandQueue queue, MappingAccess access) { |
||||||
|
return mapAsync(queue, getSize(), 0, access); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Enqueues a fill operation. This method can be used to initialize or clear |
||||||
|
* a buffer with a certain value. |
||||||
|
* @param queue the command queue |
||||||
|
* @param pattern the buffer containing the filling pattern. |
||||||
|
* The remaining bytes specify the pattern length |
||||||
|
* @param size the size in bytes to fill, must be a multiple of the pattern length |
||||||
|
* @param offset the offset in bytes into the buffer, must be a multiple of the pattern length |
||||||
|
* @return an event indicating when this operation is finished |
||||||
|
*/ |
||||||
|
public abstract Event fillAsync(CommandQueue queue, ByteBuffer pattern, long size, long offset); |
||||||
|
|
||||||
|
/** |
||||||
|
* Result of an async mapping operation, contains the event and the target byte buffer. |
||||||
|
* This is a work-around since no generic pair-structure is avaiable. |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public static class AsyncMapping { |
||||||
|
|
||||||
|
public final Event event; |
||||||
|
public final ByteBuffer buffer; |
||||||
|
|
||||||
|
public AsyncMapping(Event event, ByteBuffer buffer) { |
||||||
|
super(); |
||||||
|
this.event = event; |
||||||
|
this.buffer = buffer; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the event object indicating when the data in the mapped buffer |
||||||
|
* is available |
||||||
|
*/ |
||||||
|
public Event getEvent() { |
||||||
|
return event; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the mapped buffer, only valid when the event object signals completion |
||||||
|
*/ |
||||||
|
public ByteBuffer getBuffer() { |
||||||
|
return buffer; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Copies this buffer to the specified image. |
||||||
|
* Note that no format conversion is done. |
||||||
|
* <br> |
||||||
|
* For detailed description of the origin and region paramenter, see the |
||||||
|
* documentation of the {@link Image} class. |
||||||
|
* |
||||||
|
* @param queue the command queue |
||||||
|
* @param dest the target image |
||||||
|
* @param srcOffset the offset in bytes into this buffer |
||||||
|
* @param destOrigin the origin of the copied area |
||||||
|
* @param destRegion the size of the copied area |
||||||
|
* @return the event object |
||||||
|
*/ |
||||||
|
public abstract Event copyToImageAsync(CommandQueue queue, Image dest, long srcOffset, long[] destOrigin, long[] destRegion); |
||||||
|
|
||||||
|
/** |
||||||
|
* Aquires this buffer object for using. Only call this method if this buffer |
||||||
|
* represents a shared object from OpenGL, created with e.g. |
||||||
|
* {@link Context#bindVertexBuffer(com.jme3.scene.VertexBuffer, com.jme3.opencl.MemoryAccess) }. |
||||||
|
* This method must be called before the buffer is used. After the work is |
||||||
|
* done, the buffer must be released by calling |
||||||
|
* {@link #releaseBufferForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* so that OpenGL can use the VertexBuffer again. |
||||||
|
* @param queue the command queue |
||||||
|
* @return the event object |
||||||
|
*/ |
||||||
|
public abstract Event acquireBufferForSharingAsync(CommandQueue queue); |
||||||
|
|
||||||
|
/** |
||||||
|
* Aquires this buffer object for using. Only call this method if this buffer |
||||||
|
* represents a shared object from OpenGL, created with e.g. |
||||||
|
* {@link Context#bindVertexBuffer(com.jme3.scene.VertexBuffer, com.jme3.opencl.MemoryAccess) }. |
||||||
|
* This method must be called before the buffer is used. After the work is |
||||||
|
* done, the buffer must be released by calling |
||||||
|
* {@link #releaseBufferForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* so that OpenGL can use the VertexBuffer again. |
||||||
|
* |
||||||
|
* The generated event object is directly released. |
||||||
|
* This brings a performance improvement when the resource is e.g. directly |
||||||
|
* used by a kernel afterwards on the same queue (this implicitly waits for |
||||||
|
* this action). If you need the event, use |
||||||
|
* {@link #acquireBufferForSharingAsync(com.jme3.opencl.CommandQueue) } instead. |
||||||
|
* |
||||||
|
* @param queue the command queue |
||||||
|
*/ |
||||||
|
public void acquireBufferForSharingNoEvent(CommandQueue queue) { |
||||||
|
//default implementation, overwrite for better performance
|
||||||
|
acquireBufferForSharingAsync(queue).release(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Releases a shared buffer object. |
||||||
|
* Call this method after the buffer object was acquired by |
||||||
|
* {@link #acquireBufferForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* to hand the control back to OpenGL. |
||||||
|
* @param queue the command queue |
||||||
|
* @return the event object |
||||||
|
*/ |
||||||
|
public abstract Event releaseBufferForSharingAsync(CommandQueue queue); |
||||||
|
|
||||||
|
/** |
||||||
|
* Releases a shared buffer object. |
||||||
|
* Call this method after the buffer object was acquired by |
||||||
|
* {@link #acquireBufferForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* to hand the control back to OpenGL. |
||||||
|
* The generated event object is directly released, resulting in |
||||||
|
* performance improvements. |
||||||
|
* @param queue the command queue |
||||||
|
*/ |
||||||
|
public void releaseBufferForSharingNoEvent(CommandQueue queue) { |
||||||
|
//default implementation, overwrite for better performance
|
||||||
|
releaseBufferForSharingAsync(queue).release(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,68 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
/** |
||||||
|
* Wrapper for an OpenCL command queue. |
||||||
|
* The command queue serializes every GPU function call: By passing the same |
||||||
|
* queue to OpenCL function (buffer, image operations, kernel calls), it is |
||||||
|
* ensured that they are executed in the order in which they are passed. |
||||||
|
* <br> |
||||||
|
* Each command queue is associtated with exactly one device: that device |
||||||
|
* is specified on creation ({@link Context#createQueue(com.jme3.opencl.Device) }) |
||||||
|
* and all commands are sent to this device. |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
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 |
||||||
|
* queued commands to command_queue will eventually be submitted to the |
||||||
|
* appropriate device. There is no guarantee that they will be complete |
||||||
|
* after flush returns. |
||||||
|
*/ |
||||||
|
public abstract void flush(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Blocks until all previously queued OpenCL commands in command queue are |
||||||
|
* issued to the associated device and have completed. Finish does not |
||||||
|
* return until all previously queued commands in command queue have been |
||||||
|
* processed and completed. Finish is also a synchronization point. |
||||||
|
*/ |
||||||
|
public abstract void finish(); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,439 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
import com.jme3.asset.AssetInfo; |
||||||
|
import com.jme3.asset.AssetKey; |
||||||
|
import com.jme3.asset.AssetManager; |
||||||
|
import com.jme3.asset.AssetNotFoundException; |
||||||
|
import com.jme3.opencl.Image.ImageDescriptor; |
||||||
|
import com.jme3.opencl.Image.ImageFormat; |
||||||
|
import com.jme3.opencl.Image.ImageType; |
||||||
|
import com.jme3.scene.VertexBuffer; |
||||||
|
import com.jme3.texture.FrameBuffer; |
||||||
|
import com.jme3.texture.Texture; |
||||||
|
import java.io.BufferedReader; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStreamReader; |
||||||
|
import java.io.StringReader; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.List; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* The central OpenCL context. Every action starts from here. |
||||||
|
* The context can be obtained by {@link com.jme3.system.JmeContext#getOpenCLContext() }. |
||||||
|
* <p> |
||||||
|
* The context is used to: |
||||||
|
* <ul> |
||||||
|
* <li>Query the available devices</li> |
||||||
|
* <li>Create a command queue</li> |
||||||
|
* <li>Create buffers and images</li> |
||||||
|
* <li>Created buffers and images shared with OpenGL vertex buffers, textures and renderbuffers</li> |
||||||
|
* <li>Create program objects from source code and source files</li> |
||||||
|
* </ul> |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
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}. |
||||||
|
* They are used to create a command queue sending commands to a particular |
||||||
|
* device, see {@link #createQueue(com.jme3.opencl.Device) }. |
||||||
|
* Also, device capabilities, like the supported OpenCL version, extensions, |
||||||
|
* memory size and so on, are queried over the Device instances. |
||||||
|
* <br> |
||||||
|
* The available devices were specified by a {@link PlatformChooser}. |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public abstract List<? extends Device> getDevices(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #createQueue(com.jme3.opencl.Device) }, |
||||||
|
* just uses the first device returned by {@link #getDevices() }. |
||||||
|
* @return the command queue |
||||||
|
*/ |
||||||
|
public CommandQueue createQueue() { |
||||||
|
return createQueue(getDevices().get(0)); |
||||||
|
} |
||||||
|
/** |
||||||
|
* Creates a command queue sending commands to the specified device. |
||||||
|
* The device must be an entry of {@link #getDevices() }. |
||||||
|
* @param device the target device |
||||||
|
* @return the command queue |
||||||
|
*/ |
||||||
|
public abstract CommandQueue createQueue(Device device); |
||||||
|
|
||||||
|
/** |
||||||
|
* Allocates a new buffer of the specific size and access type on the device. |
||||||
|
* @param size the size of the buffer in bytes |
||||||
|
* @param access the allowed access of this buffer from kernel code |
||||||
|
* @return the new buffer |
||||||
|
*/ |
||||||
|
public abstract Buffer createBuffer(long size, MemoryAccess access); |
||||||
|
/** |
||||||
|
* Alternative version of {@link #createBuffer(long, com.jme3.opencl.MemoryAccess) }, |
||||||
|
* creates a buffer with read and write access. |
||||||
|
* @param size the size of the buffer in bytes |
||||||
|
* @return the new buffer |
||||||
|
*/ |
||||||
|
public Buffer createBuffer(long size) { |
||||||
|
return createBuffer(size, MemoryAccess.READ_WRITE); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new buffer wrapping the specific host memory. This host memory |
||||||
|
* specified by a ByteBuffer can then be used directly by kernel code, |
||||||
|
* although the access might be slower than with native buffers |
||||||
|
* created by {@link #createBuffer(long, com.jme3.opencl.MemoryAccess) }. |
||||||
|
* @param data the host buffer to use |
||||||
|
* @param access the allowed access of this buffer from kernel code |
||||||
|
* @return the new buffer |
||||||
|
*/ |
||||||
|
public abstract Buffer createBufferFromHost(ByteBuffer data, MemoryAccess access); |
||||||
|
/** |
||||||
|
* Alternative version of {@link #createBufferFromHost(java.nio.ByteBuffer, com.jme3.opencl.MemoryAccess) }, |
||||||
|
* creates a buffer with read and write access. |
||||||
|
* @param data the host buffer to use |
||||||
|
* @return the new buffer |
||||||
|
*/ |
||||||
|
public Buffer createBufferFromHost(ByteBuffer data) { |
||||||
|
return createBufferFromHost(data, MemoryAccess.READ_WRITE); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new 1D, 2D, 3D image.<br> |
||||||
|
* {@code ImageFormat} specifies the element type and order, like RGBA of floats.<br> |
||||||
|
* {@code ImageDescriptor} specifies the dimension of the image.<br> |
||||||
|
* Furthermore, a ByteBuffer can be specified in the ImageDescriptor together |
||||||
|
* with row and slice pitches. This buffer is then used to store the image. |
||||||
|
* If no ByteBuffer is specified, a new buffer is allocated (this is the |
||||||
|
* normal behaviour). |
||||||
|
* @param access the allowed access of this image from kernel code |
||||||
|
* @param format the image format |
||||||
|
* @param descr the image descriptor |
||||||
|
* @return the new image object |
||||||
|
*/ |
||||||
|
public abstract Image createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr); |
||||||
|
//TODO: add simplified methods for 1D, 2D, 3D textures
|
||||||
|
|
||||||
|
/** |
||||||
|
* Queries all supported image formats for a specified memory access and |
||||||
|
* image type. |
||||||
|
* <br> |
||||||
|
* Note that the returned array may contain {@code ImageFormat} objects |
||||||
|
* where {@code ImageChannelType} or {@code ImageChannelOrder} are {@code null} |
||||||
|
* (or both). This is the case when the device supports new formats that |
||||||
|
* are not included in this wrapper yet. |
||||||
|
* @param access the memory access type |
||||||
|
* @param type the image type (1D, 2D, 3D, ...) |
||||||
|
* @return an array of all supported image formats |
||||||
|
*/ |
||||||
|
public abstract ImageFormat[] querySupportedFormats(MemoryAccess access, ImageType type); |
||||||
|
|
||||||
|
//Interop
|
||||||
|
/** |
||||||
|
* Creates a shared buffer from a VertexBuffer. |
||||||
|
* The returned buffer and the vertex buffer operate on the same memory, |
||||||
|
* changes in one view are visible in the other view. |
||||||
|
* This can be used to modify meshes directly from OpenCL (e.g. for particle systems). |
||||||
|
* <br> |
||||||
|
* <b>Note:</b> The vertex buffer must already been uploaded to the GPU, |
||||||
|
* i.e. it must be used at least once for drawing. |
||||||
|
* <p> |
||||||
|
* Before the returned buffer can be used, it must be acquried explicitly |
||||||
|
* by {@link Buffer#acquireBufferForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* and after modifying it, released by {@link Buffer#releaseBufferForSharingAsync(com.jme3.opencl.CommandQueue) }. |
||||||
|
* This is needed so that OpenGL and OpenCL operations do not interfer with each other. |
||||||
|
* @param vb the vertex buffer to share |
||||||
|
* @param access the memory access for the kernel |
||||||
|
* @return the new buffer |
||||||
|
*/ |
||||||
|
public abstract Buffer bindVertexBuffer(VertexBuffer vb, MemoryAccess access); |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a shared image object from a jME3-image. |
||||||
|
* The returned image shares the same memory with the jME3-image, changes |
||||||
|
* in one view are visible in the other view. |
||||||
|
* This can be used to modify textures and images directly from OpenCL |
||||||
|
* (e.g. for post processing effects and other texture effects). |
||||||
|
* <br> |
||||||
|
* <b>Note:</b> The image must already been uploaded to the GPU, |
||||||
|
* i.e. it must be used at least once for drawing. |
||||||
|
* <p> |
||||||
|
* Before the returned image can be used, it must be acquried explicitly |
||||||
|
* by {@link Image#acquireImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* and after modifying it, released by {@link Image#releaseImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* This is needed so that OpenGL and OpenCL operations do not interfer with each other. |
||||||
|
* |
||||||
|
* @param image the jME3 image object |
||||||
|
* @param textureType the texture type (1D, 2D, 3D), since this is not stored in the image |
||||||
|
* @param miplevel the mipmap level that should be shared |
||||||
|
* @param access the allowed memory access for kernels |
||||||
|
* @return the OpenCL image |
||||||
|
*/ |
||||||
|
public abstract Image bindImage(com.jme3.texture.Image image, Texture.Type textureType, int miplevel, MemoryAccess access); |
||||||
|
/** |
||||||
|
* Creates a shared image object from a jME3 texture. |
||||||
|
* The returned image shares the same memory with the jME3 texture, changes |
||||||
|
* in one view are visible in the other view. |
||||||
|
* This can be used to modify textures and images directly from OpenCL |
||||||
|
* (e.g. for post processing effects and other texture effects). |
||||||
|
* <br> |
||||||
|
* <b>Note:</b> The image must already been uploaded to the GPU, |
||||||
|
* i.e. it must be used at least once for drawing. |
||||||
|
* <p> |
||||||
|
* Before the returned image can be used, it must be acquried explicitly |
||||||
|
* by {@link Image#acquireImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* and after modifying it, released by {@link Image#releaseImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* This is needed so that OpenGL and OpenCL operations do not interfer with each other. |
||||||
|
* <p> |
||||||
|
* This method is equivalent to calling |
||||||
|
* {@code bindImage(texture.getImage(), texture.getType(), miplevel, access)}. |
||||||
|
* |
||||||
|
* @param texture the jME3 texture |
||||||
|
* @param miplevel the mipmap level that should be shared |
||||||
|
* @param access the allowed memory access for kernels |
||||||
|
* @return the OpenCL image |
||||||
|
*/ |
||||||
|
public Image bindImage(Texture texture, int miplevel, MemoryAccess access) { |
||||||
|
return bindImage(texture.getImage(), texture.getType(), miplevel, access); |
||||||
|
} |
||||||
|
/** |
||||||
|
* Alternative version to {@link #bindImage(com.jme3.texture.Texture, int, com.jme3.opencl.MemoryAccess) }, |
||||||
|
* uses {@code miplevel=0}. |
||||||
|
* @param texture the jME3 texture |
||||||
|
* @param access the allowed memory access for kernels |
||||||
|
* @return the OpenCL image |
||||||
|
*/ |
||||||
|
public Image bindImage(Texture texture, MemoryAccess access) { |
||||||
|
return bindImage(texture, 0, access); |
||||||
|
} |
||||||
|
/** |
||||||
|
* Creates a shared image object from a jME3 render buffer. |
||||||
|
* The returned image shares the same memory with the jME3 render buffer, changes |
||||||
|
* in one view are visible in the other view. |
||||||
|
* <br> |
||||||
|
* This can be used as an alternative to post processing effects |
||||||
|
* (e.g. reduce sum operations, needed e.g. for tone mapping). |
||||||
|
* <br> |
||||||
|
* <b>Note:</b> The renderbuffer must already been uploaded to the GPU, |
||||||
|
* i.e. it must be used at least once for drawing. |
||||||
|
* <p> |
||||||
|
* Before the returned image can be used, it must be acquried explicitly |
||||||
|
* by {@link Image#acquireImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* and after modifying it, released by {@link Image#releaseImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* This is needed so that OpenGL and OpenCL operations do not interfer with each other. |
||||||
|
* |
||||||
|
* @param buffer |
||||||
|
* @param access |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public Image bindRenderBuffer(FrameBuffer.RenderBuffer buffer, MemoryAccess access) { |
||||||
|
if (buffer.getTexture() == null) { |
||||||
|
return bindPureRenderBuffer(buffer, access); |
||||||
|
} else { |
||||||
|
return bindImage(buffer.getTexture(), access); |
||||||
|
} |
||||||
|
} |
||||||
|
protected abstract Image bindPureRenderBuffer(FrameBuffer.RenderBuffer buffer, MemoryAccess access); |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a program object from the provided source code. |
||||||
|
* The program still needs to be compiled using {@link Program#build() }. |
||||||
|
* |
||||||
|
* @param sourceCode the source code |
||||||
|
* @return the program object |
||||||
|
*/ |
||||||
|
public abstract Program createProgramFromSourceCode(String sourceCode); |
||||||
|
|
||||||
|
/** |
||||||
|
* Resolves dependencies (using {@code #include } in the source code) |
||||||
|
* and delegates the combined source code to |
||||||
|
* {@link #createProgramFromSourceCode(java.lang.String) }. |
||||||
|
* Important: only absolute paths are allowed. |
||||||
|
* @param sourceCode the original source code |
||||||
|
* @param assetManager the asset manager to load the files |
||||||
|
* @return the created program object |
||||||
|
* @throws AssetNotFoundException if a dependency could not be loaded |
||||||
|
*/ |
||||||
|
public Program createProgramFromSourceCodeWithDependencies(String sourceCode, AssetManager assetManager) { |
||||||
|
StringBuilder builder = new StringBuilder(sourceCode.length()); |
||||||
|
BufferedReader reader = new BufferedReader(new StringReader(sourceCode)); |
||||||
|
try { |
||||||
|
buildSourcesRec(reader, builder, assetManager); |
||||||
|
} catch (IOException ex) { |
||||||
|
throw new AssetNotFoundException("Unable to read a dependency file", ex); |
||||||
|
} |
||||||
|
return createProgramFromSourceCode(builder.toString()); |
||||||
|
} |
||||||
|
private void buildSourcesRec(BufferedReader reader, StringBuilder builder, AssetManager assetManager) throws IOException { |
||||||
|
String ln; |
||||||
|
while ((ln = reader.readLine()) != null) { |
||||||
|
if (ln.trim().startsWith("#import ")) { |
||||||
|
ln = ln.trim().substring(8).trim(); |
||||||
|
if (ln.startsWith("\"")) { |
||||||
|
ln = ln.substring(1); |
||||||
|
} |
||||||
|
if (ln.endsWith("\"")) { |
||||||
|
ln = ln.substring(0, ln.length()-1); |
||||||
|
} |
||||||
|
AssetInfo info = assetManager.locateAsset(new AssetKey<String>(ln)); |
||||||
|
if (info == null) { |
||||||
|
throw new AssetNotFoundException("Unable to load source file \""+ln+"\""); |
||||||
|
} |
||||||
|
try (BufferedReader r = new BufferedReader(new InputStreamReader(info.openStream()))) { |
||||||
|
builder.append("//-- begin import ").append(ln).append(" --\n"); |
||||||
|
buildSourcesRec(r, builder, assetManager); |
||||||
|
builder.append("//-- end import ").append(ln).append(" --\n"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
builder.append(ln).append('\n'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a program object from the provided source code and files. |
||||||
|
* The source code is made up from the specified include string first, |
||||||
|
* then all files specified by the resource array (array of asset paths) |
||||||
|
* are loaded by the provided asset manager and appended to the source code. |
||||||
|
* <p> |
||||||
|
* The typical use case is: |
||||||
|
* <ul> |
||||||
|
* <li>The include string contains some compiler constants like the grid size </li> |
||||||
|
* <li>Some common OpenCL files used as libraries (Convention: file names end with {@code .clh}</li> |
||||||
|
* <li>One main OpenCL file containing the actual kernels (Convention: file name ends with {@code .cl})</li> |
||||||
|
* </ul> |
||||||
|
* |
||||||
|
* After the files were combined, additional include statements are resolved |
||||||
|
* by {@link #createProgramFromSourceCodeWithDependencies(java.lang.String, com.jme3.asset.AssetManager) }. |
||||||
|
* |
||||||
|
* @param assetManager the asset manager used to load the files |
||||||
|
* @param include an additional include string |
||||||
|
* @param resources an array of asset paths pointing to OpenCL source files |
||||||
|
* @return the new program objects |
||||||
|
* @throws AssetNotFoundException if a file could not be loaded |
||||||
|
*/ |
||||||
|
public Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, String... resources) { |
||||||
|
return createProgramFromSourceFilesWithInclude(assetManager, include, Arrays.asList(resources)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a program object from the provided source code and files. |
||||||
|
* The source code is made up from the specified include string first, |
||||||
|
* then all files specified by the resource array (array of asset paths) |
||||||
|
* are loaded by the provided asset manager and appended to the source code. |
||||||
|
* <p> |
||||||
|
* The typical use case is: |
||||||
|
* <ul> |
||||||
|
* <li>The include string contains some compiler constants like the grid size </li> |
||||||
|
* <li>Some common OpenCL files used as libraries (Convention: file names end with {@code .clh}</li> |
||||||
|
* <li>One main OpenCL file containing the actual kernels (Convention: file name ends with {@code .cl})</li> |
||||||
|
* </ul> |
||||||
|
* |
||||||
|
* After the files were combined, additional include statements are resolved |
||||||
|
* by {@link #createProgramFromSourceCodeWithDependencies(java.lang.String, com.jme3.asset.AssetManager) }. |
||||||
|
* |
||||||
|
* @param assetManager the asset manager used to load the files |
||||||
|
* @param include an additional include string |
||||||
|
* @param resources an array of asset paths pointing to OpenCL source files |
||||||
|
* @return the new program objects |
||||||
|
* @throws AssetNotFoundException if a file could not be loaded |
||||||
|
*/ |
||||||
|
public Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, List<String> resources) { |
||||||
|
StringBuilder str = new StringBuilder(); |
||||||
|
str.append(include); |
||||||
|
for (String res : resources) { |
||||||
|
AssetInfo info = assetManager.locateAsset(new AssetKey<String>(res)); |
||||||
|
if (info == null) { |
||||||
|
throw new AssetNotFoundException("Unable to load source file \""+res+"\""); |
||||||
|
} |
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(info.openStream()))) { |
||||||
|
while (true) { |
||||||
|
String line = reader.readLine(); |
||||||
|
if (line == null) { |
||||||
|
break; |
||||||
|
} |
||||||
|
str.append(line).append('\n'); |
||||||
|
} |
||||||
|
} catch (IOException ex) { |
||||||
|
LOG.log(Level.WARNING, "unable to load source file '"+res+"'", ex); |
||||||
|
} |
||||||
|
} |
||||||
|
return createProgramFromSourceCodeWithDependencies(str.toString(), assetManager); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #createProgramFromSourceFilesWithInclude(com.jme3.asset.AssetManager, java.lang.String, java.lang.String...) } |
||||||
|
* with an empty include string |
||||||
|
* @throws AssetNotFoundException if a file could not be loaded |
||||||
|
*/ |
||||||
|
public Program createProgramFromSourceFiles(AssetManager assetManager, String... resources) { |
||||||
|
return createProgramFromSourceFilesWithInclude(assetManager, "", resources); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Alternative version of {@link #createProgramFromSourceFilesWithInclude(com.jme3.asset.AssetManager, java.lang.String, java.util.List) } |
||||||
|
* with an empty include string |
||||||
|
* @throws AssetNotFoundException if a file could not be loaded |
||||||
|
*/ |
||||||
|
public Program createProgramFromSourceFiles(AssetManager assetManager, List<String> resources) { |
||||||
|
return createProgramFromSourceFilesWithInclude(assetManager, "", resources); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a program from the specified binaries. |
||||||
|
* The binaries are created by {@link Program#getBinary(com.jme3.opencl.Device) }. |
||||||
|
* The returned program still needs to be build using |
||||||
|
* {@link Program#build(java.lang.String, com.jme3.opencl.Device...) }. |
||||||
|
* <b>Important:</b>The device passed to {@code Program.getBinary(..)}, |
||||||
|
* this method and {@code Program#build(..)} must be the same. |
||||||
|
* |
||||||
|
* The binaries are used to build a program cache across multiple launches |
||||||
|
* of the application. The programs build mach faster from binaries than |
||||||
|
* from sources. |
||||||
|
* |
||||||
|
* @param binaries the binaries |
||||||
|
* @param device the device to use |
||||||
|
* @return the new program |
||||||
|
*/ |
||||||
|
public abstract Program createProgramFromBinary(ByteBuffer binaries, Device device); |
||||||
|
} |
@ -0,0 +1,91 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* A default implementation of {@link PlatformChooser}. |
||||||
|
* It favors GPU devices with OpenGL sharing, then any devices with OpenGL sharing, |
||||||
|
* then any possible device. |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class DefaultPlatformChooser implements PlatformChooser { |
||||||
|
private static final Logger LOG = Logger.getLogger(DefaultPlatformChooser.class.getName()); |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<? extends Device> chooseDevices(List<? extends Platform> platforms) { |
||||||
|
ArrayList<Device> result = new ArrayList<Device>(); |
||||||
|
for (Platform p : platforms) { |
||||||
|
if (!p.hasOpenGLInterop()) { |
||||||
|
continue; //must support interop
|
||||||
|
} |
||||||
|
for (Device d : p.getDevices()) { |
||||||
|
if (d.hasOpenGLInterop() && d.getDeviceType()==Device.DeviceType.GPU) { |
||||||
|
result.add(d); //GPU prefered
|
||||||
|
} |
||||||
|
} |
||||||
|
if (!result.isEmpty()) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
|
//no GPU devices found, try all
|
||||||
|
for (Platform p : platforms) { |
||||||
|
if (!p.hasOpenGLInterop()) { |
||||||
|
continue; //must support interop
|
||||||
|
} |
||||||
|
for (Device d : p.getDevices()) { |
||||||
|
if (d.hasOpenGLInterop()) { |
||||||
|
result.add(d); //just interop needed
|
||||||
|
} |
||||||
|
} |
||||||
|
if (!result.isEmpty()) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
|
//still no one found, try without interop
|
||||||
|
LOG.warning("No device with OpenCL-OpenGL-interop found, try without"); |
||||||
|
for (Platform p : platforms) { |
||||||
|
for (Device d : p.getDevices()) { |
||||||
|
result.add(d); |
||||||
|
} |
||||||
|
if (!result.isEmpty()) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
|
//no devices available at all!
|
||||||
|
return result; //result is empty
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,311 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
import java.util.Collection; |
||||||
|
|
||||||
|
/** |
||||||
|
* Represents a hardware device actually running the OpenCL kernels. |
||||||
|
* A {@link Context} can be accociated with multiple {@code Devices} |
||||||
|
* that all belong to the same {@link Platform}. |
||||||
|
* For execution, a single device must be chosen and passed to a command |
||||||
|
* queue ({@link Context#createQueue(com.jme3.opencl.Device) }). |
||||||
|
* <p> |
||||||
|
* This class is used to query the capabilities of the underlying device. |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public interface Device { |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the platform accociated with this device |
||||||
|
*/ |
||||||
|
Platform getPlatform(); |
||||||
|
|
||||||
|
/** |
||||||
|
* The device type |
||||||
|
*/ |
||||||
|
public static enum DeviceType { |
||||||
|
DEFAULT, |
||||||
|
CPU, |
||||||
|
GPU, |
||||||
|
ACCELEARTOR, |
||||||
|
ALL |
||||||
|
} |
||||||
|
/** |
||||||
|
* @return queries the device type |
||||||
|
*/ |
||||||
|
DeviceType getDeviceType(); |
||||||
|
/** |
||||||
|
* @return the vendor id |
||||||
|
*/ |
||||||
|
int getVendorId(); |
||||||
|
/** |
||||||
|
* checks if this device is available at all, must always be tested |
||||||
|
* @return checks if this device is available at all, must always be tested |
||||||
|
*/ |
||||||
|
boolean isAvailable(); |
||||||
|
|
||||||
|
/** |
||||||
|
* @return if this device has a compiler for kernel code |
||||||
|
*/ |
||||||
|
boolean hasCompiler(); |
||||||
|
/** |
||||||
|
* @return supports double precision floats (64 bit) |
||||||
|
*/ |
||||||
|
boolean hasDouble(); |
||||||
|
/** |
||||||
|
* @return supports half precision floats (16 bit) |
||||||
|
*/ |
||||||
|
boolean hasHalfFloat(); |
||||||
|
/** |
||||||
|
* @return supports error correction for every access to global or constant memory |
||||||
|
*/ |
||||||
|
boolean hasErrorCorrectingMemory(); |
||||||
|
/** |
||||||
|
* @return supports unified virtual memory (OpenCL 2.0) |
||||||
|
*/ |
||||||
|
boolean hasUnifiedMemory(); |
||||||
|
/** |
||||||
|
* @return supports images |
||||||
|
*/ |
||||||
|
boolean hasImageSupport(); |
||||||
|
/** |
||||||
|
* @return supports writes to 3d images (this is an extension) |
||||||
|
*/ |
||||||
|
boolean hasWritableImage3D(); |
||||||
|
/** |
||||||
|
* @return supports sharing with OpenGL |
||||||
|
*/ |
||||||
|
boolean hasOpenGLInterop(); |
||||||
|
/** |
||||||
|
* Explicetly tests for the availability of the specified extension |
||||||
|
* @param extension the name of the extension |
||||||
|
* @return {@code true} iff this extension is supported |
||||||
|
*/ |
||||||
|
boolean hasExtension(String extension); |
||||||
|
/** |
||||||
|
* Lists all available extensions |
||||||
|
* @return all available extensions |
||||||
|
*/ |
||||||
|
Collection<? extends String> getExtensions(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the number of parallel compute units on |
||||||
|
* the OpenCL device. A work-group |
||||||
|
* executes on a single compute unit. The |
||||||
|
* minimum value is 1. |
||||||
|
* @return the number of parallel compute units |
||||||
|
* @see #getMaximumWorkItemDimensions() |
||||||
|
* @see #getMaximumWorkItemSizes() |
||||||
|
*/ |
||||||
|
int getComputeUnits(); |
||||||
|
/** |
||||||
|
* @return maximum clock frequency of the device in MHz |
||||||
|
*/ |
||||||
|
int getClockFrequency(); |
||||||
|
/** |
||||||
|
* Returns the default compute device address space |
||||||
|
* size specified as an unsigned integer value |
||||||
|
* in bits. Currently supported values are 32 |
||||||
|
* or 64 bits. |
||||||
|
* @return the size of an adress |
||||||
|
*/ |
||||||
|
int getAddressBits(); |
||||||
|
/** |
||||||
|
* @return {@code true} if this device is little endian |
||||||
|
*/ |
||||||
|
boolean isLittleEndian(); |
||||||
|
|
||||||
|
/** |
||||||
|
* The maximum dimension that specify the local and global work item ids. |
||||||
|
* You can always assume to be this at least 3. |
||||||
|
* Therefore, the ids are always three integers x,y,z. |
||||||
|
* @return the maximum dimension of work item ids |
||||||
|
*/ |
||||||
|
long getMaximumWorkItemDimensions(); |
||||||
|
/** |
||||||
|
* Maximum number of work-items that can be specified in each dimension of the |
||||||
|
* work-group to {@link Kernel#Run2(com.jme3.opencl.CommandQueue, com.jme3.opencl.WorkSize, com.jme3.opencl.WorkSize, java.lang.Object...) }. |
||||||
|
* The array has a length of at least 3. |
||||||
|
* @return the maximum size of the work group in each dimension |
||||||
|
*/ |
||||||
|
long[] getMaximumWorkItemSizes(); |
||||||
|
/** |
||||||
|
* Maximum number of work-items in a |
||||||
|
* work-group executing a kernel on a single |
||||||
|
* compute unit, using the data parallel |
||||||
|
* execution model. |
||||||
|
* @return maximum number of work-items in a work-group |
||||||
|
*/ |
||||||
|
long getMaxiumWorkItemsPerGroup(); |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the maximum number of samples that can be used in a kernel |
||||||
|
*/ |
||||||
|
int getMaximumSamplers(); |
||||||
|
/** |
||||||
|
* @return the maximum number of images that can be used for reading in a kernel |
||||||
|
*/ |
||||||
|
int getMaximumReadImages(); |
||||||
|
/** |
||||||
|
* @return the maximum number of images that can be used for writing in a kernel |
||||||
|
*/ |
||||||
|
int getMaximumWriteImages(); |
||||||
|
/** |
||||||
|
* Queries the maximal size of a 2D image |
||||||
|
* @return an array of length 2 with the maximal size of a 2D image |
||||||
|
*/ |
||||||
|
long[] getMaximumImage2DSize(); |
||||||
|
/** |
||||||
|
* Queries the maximal size of a 3D image |
||||||
|
* @return an array of length 3 with the maximal size of a 3D image |
||||||
|
*/ |
||||||
|
long[] getMaximumImage3DSize(); |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the maximal size of a memory object (buffer and image) in bytes |
||||||
|
*/ |
||||||
|
long getMaximumAllocationSize(); |
||||||
|
/** |
||||||
|
* @return the total available global memory in bytes |
||||||
|
*/ |
||||||
|
long getGlobalMemorySize(); |
||||||
|
/** |
||||||
|
* @return the total available local memory in bytes |
||||||
|
*/ |
||||||
|
long getLocalMemorySize(); |
||||||
|
/** |
||||||
|
* Returns the maximal size of a constant buffer. |
||||||
|
* <br> |
||||||
|
* Constant buffers are normal buffer objects, but passed to the kernel |
||||||
|
* with the special declaration {@code __constant BUFFER_TYPE* BUFFER_NAME}. |
||||||
|
* Because they have a special caching, their size is usually very limited. |
||||||
|
* |
||||||
|
* @return the maximal size of a constant buffer |
||||||
|
*/ |
||||||
|
long getMaximumConstantBufferSize(); |
||||||
|
/** |
||||||
|
* @return the maximal number of constant buffer arguments in a kernel call |
||||||
|
*/ |
||||||
|
int getMaximumConstantArguments(); |
||||||
|
|
||||||
|
//TODO: cache, prefered sizes properties
|
||||||
|
/** |
||||||
|
* OpenCL profile string. Returns the profile name supported by the device. |
||||||
|
* The profile name returned can be one of the following strings:<br> |
||||||
|
* FULL_PROFILE – if the device supports the OpenCL specification |
||||||
|
* (functionality defined as part of the core specification and does not |
||||||
|
* require any extensions to be supported).<br> |
||||||
|
* EMBEDDED_PROFILE - if the device supports the OpenCL embedded profile. |
||||||
|
* |
||||||
|
* @return the profile string |
||||||
|
*/ |
||||||
|
String getProfile(); |
||||||
|
/** |
||||||
|
* OpenCL version string. Returns the OpenCL version supported by the |
||||||
|
* device. This version string has the following format: OpenCL space |
||||||
|
* major_version.minor_version space vendor-specific information. |
||||||
|
* <br> |
||||||
|
* E.g. OpenCL 1.1, OpenCL 1.2, OpenCL 2.0 |
||||||
|
* |
||||||
|
* @return the version string |
||||||
|
*/ |
||||||
|
String getVersion(); |
||||||
|
/** |
||||||
|
* Extracts the major version from the version string |
||||||
|
* @return the major version |
||||||
|
* @see #getVersion() |
||||||
|
*/ |
||||||
|
int getVersionMajor(); |
||||||
|
/** |
||||||
|
* Extracts the minor version from the version string |
||||||
|
* @return the minor version |
||||||
|
* @see #getVersion() } |
||||||
|
*/ |
||||||
|
int getVersionMinor(); |
||||||
|
|
||||||
|
/** |
||||||
|
* OpenCL C version string. Returns the highest OpenCL C version supported |
||||||
|
* by the compiler for this device that is not of type |
||||||
|
* CL_DEVICE_TYPE_CUSTOM. This version string has the following format: |
||||||
|
* OpenCL space C space major_version.minor_version space vendor-specific |
||||||
|
* information.<br> |
||||||
|
* The major_version.minor_version value returned must be 1.2 if |
||||||
|
* CL_DEVICE_VERSION is OpenCL 1.2. The major_version.minor_version value |
||||||
|
* returned must be 1.1 if CL_DEVICE_VERSION is OpenCL 1.1. The |
||||||
|
* major_version.minor_version value returned can be 1.0 or 1.1 if |
||||||
|
* CL_DEVICE_VERSION is OpenCL 1.0. |
||||||
|
* |
||||||
|
* @return the compiler version |
||||||
|
*/ |
||||||
|
String getCompilerVersion(); |
||||||
|
/** |
||||||
|
* Extracts the major version from the compiler version |
||||||
|
* @return the major compiler version |
||||||
|
* @see #getCompilerVersion() |
||||||
|
*/ |
||||||
|
int getCompilerVersionMajor(); |
||||||
|
/** |
||||||
|
* Extracts the minor version from the compiler version |
||||||
|
* @return the minor compiler version |
||||||
|
* @see #getCompilerVersion() |
||||||
|
*/ |
||||||
|
int getCompilerVersionMinor(); |
||||||
|
/** |
||||||
|
* @return the OpenCL software driver version string in the form |
||||||
|
* major_number.minor_number |
||||||
|
*/ |
||||||
|
String getDriverVersion(); |
||||||
|
/** |
||||||
|
* Extracts the major version from the driver version |
||||||
|
* @return the major driver version |
||||||
|
* @see #getDriverVersion() |
||||||
|
*/ |
||||||
|
int getDriverVersionMajor(); |
||||||
|
/** |
||||||
|
* Extracts the minor version from the driver version |
||||||
|
* @return the minor driver version |
||||||
|
* @see #getDriverVersion() |
||||||
|
*/ |
||||||
|
int getDriverVersionMinor(); |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the device name |
||||||
|
*/ |
||||||
|
String getName(); |
||||||
|
/** |
||||||
|
* @return the vendor |
||||||
|
*/ |
||||||
|
String getVendor(); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
/** |
||||||
|
* Wrapper for an OpenCL Event object. |
||||||
|
* Events are returned from kernel launches and all asynchronous operations. |
||||||
|
* They allow to test if the action has completed and to block until the operation |
||||||
|
* is done. |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public abstract class Event extends AbstractOpenCLObject { |
||||||
|
|
||||||
|
protected Event(ObjectReleaser releaser) { |
||||||
|
super(releaser); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Waits until the action has finished (blocking). |
||||||
|
* This automatically releases the event. |
||||||
|
*/ |
||||||
|
public abstract void waitForFinished(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Tests if the action is completed. |
||||||
|
* If the action is completed, the event is released. |
||||||
|
* @return {@code true} if the action is completed |
||||||
|
*/ |
||||||
|
public abstract boolean isCompleted(); |
||||||
|
} |
@ -0,0 +1,537 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
import com.jme3.math.ColorRGBA; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.util.Objects; |
||||||
|
|
||||||
|
/** |
||||||
|
* Wrapper for an OpenCL image. |
||||||
|
* <br> |
||||||
|
* An image object is similar to a {@link Buffer}, but with a specific element |
||||||
|
* format and buffer structure. |
||||||
|
* <br> |
||||||
|
* The image is specified by the {@link ImageDescriptor}, specifying |
||||||
|
* the extend and dimension of the image, and {@link ImageFormat}, specifying |
||||||
|
* the type of each pixel. |
||||||
|
* <br> |
||||||
|
* An image is created from scratch using |
||||||
|
* {@link Context#createImage(com.jme3.opencl.MemoryAccess, com.jme3.opencl.Image.ImageFormat, com.jme3.opencl.Image.ImageDescriptor) } |
||||||
|
* or from OpenGL by |
||||||
|
* {@link Context#bindImage(com.jme3.texture.Image, com.jme3.texture.Texture.Type, int, com.jme3.opencl.MemoryAccess) } |
||||||
|
* (and alternative versions). |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* Most methods take long arrays as input: {@code long[] origin} and {@code long[] region}. |
||||||
|
* Both are arrays of length 3. |
||||||
|
* <br> |
||||||
|
* <b>origin</b> defines the (x, y, z) offset in pixels in the 1D, 2D or 3D |
||||||
|
* image, the (x, y) offset and the image index in the 2D image array or the (x) |
||||||
|
* offset and the image index in the 1D image array. If image is a 2D image |
||||||
|
* object, origin[2] must be 0. If image is a 1D image or 1D image buffer |
||||||
|
* object, origin[1] and origin[2] must be 0. If image is a 1D image array |
||||||
|
* object, origin[2] must be 0. If image is a 1D image array object, origin[1] |
||||||
|
* describes the image index in the 1D image array. If image is a 2D image array |
||||||
|
* object, origin[2] describes the image index in the 2D image array. |
||||||
|
* <br> |
||||||
|
* <b>region</b> defines the (width, height, depth) in pixels of the 1D, 2D or |
||||||
|
* 3D rectangle, the (width, height) in pixels of the 2D rectangle and the |
||||||
|
* number of images of a 2D image array or the (width) in pixels of the 1D |
||||||
|
* rectangle and the number of images of a 1D image array. If image is a 2D |
||||||
|
* image object, region[2] must be 1. If image is a 1D image or 1D image buffer |
||||||
|
* object, region[1] and region[2] must be 1. If image is a 1D image array |
||||||
|
* object, region[2] must be 1. The values in region cannot be 0. |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public abstract class Image extends AbstractOpenCLObject { |
||||||
|
|
||||||
|
/** |
||||||
|
* {@code ImageChannelType} describes the size of the channel data type. |
||||||
|
*/ |
||||||
|
public static enum ImageChannelType { |
||||||
|
SNORM_INT8, |
||||||
|
SNORM_INT16, |
||||||
|
UNORM_INT8, |
||||||
|
UNORM_INT16, |
||||||
|
UNORM_SHORT_565, |
||||||
|
UNORM_SHORT_555, |
||||||
|
UNORM_INT_101010, |
||||||
|
SIGNED_INT8, |
||||||
|
SIGNED_INT16, |
||||||
|
SIGNED_INT32, |
||||||
|
UNSIGNED_INT8, |
||||||
|
UNSIGNED_INT16, |
||||||
|
UNSIGNED_INT32, |
||||||
|
HALF_FLOAT, |
||||||
|
FLOAT |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@code ImageChannelOrder} specifies the number of channels and the channel layout i.e. the |
||||||
|
memory layout in which channels are stored in the image. |
||||||
|
*/ |
||||||
|
public static enum ImageChannelOrder { |
||||||
|
R, Rx, A, |
||||||
|
INTENSITY, |
||||||
|
LUMINANCE, |
||||||
|
RG, RGx, RA, |
||||||
|
RGB, RGBx, |
||||||
|
RGBA, |
||||||
|
ARGB, BGRA |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Describes the image format, consisting of |
||||||
|
* {@link ImageChannelOrder} and {@link ImageChannelType}. |
||||||
|
*/ |
||||||
|
public static class ImageFormat { //Struct
|
||||||
|
public ImageChannelOrder channelOrder; |
||||||
|
public ImageChannelType channelType; |
||||||
|
|
||||||
|
public ImageFormat() { |
||||||
|
} |
||||||
|
|
||||||
|
public ImageFormat(ImageChannelOrder channelOrder, ImageChannelType channelType) { |
||||||
|
this.channelOrder = channelOrder; |
||||||
|
this.channelType = channelType; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return "ImageFormat{" + "channelOrder=" + channelOrder + ", channelType=" + channelType + '}'; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int hashCode() { |
||||||
|
int hash = 5; |
||||||
|
hash = 61 * hash + Objects.hashCode(this.channelOrder); |
||||||
|
hash = 61 * hash + Objects.hashCode(this.channelType); |
||||||
|
return hash; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean equals(Object obj) { |
||||||
|
if (obj == null) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (getClass() != obj.getClass()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
final ImageFormat other = (ImageFormat) obj; |
||||||
|
if (this.channelOrder != other.channelOrder) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (this.channelType != other.channelType) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* The possible image types / dimensions. |
||||||
|
*/ |
||||||
|
public static enum ImageType { |
||||||
|
IMAGE_1D, |
||||||
|
IMAGE_1D_BUFFER, |
||||||
|
IMAGE_2D, |
||||||
|
IMAGE_3D, |
||||||
|
IMAGE_1D_ARRAY, |
||||||
|
IMAGE_2D_ARRAY |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* The image descriptor structure describes the type and dimensions of the image or image array. |
||||||
|
* <p> |
||||||
|
* There exists two constructors:<br> |
||||||
|
* {@link #ImageDescriptor(com.jme3.opencl.Image.ImageType, long, long, long, long) } |
||||||
|
* is used when an image with new memory should be created (used most often).<br> |
||||||
|
* {@link #ImageDescriptor(com.jme3.opencl.Image.ImageType, long, long, long, long, long, long, java.nio.ByteBuffer) } |
||||||
|
* creates an image using the provided {@code ByteBuffer} as source. |
||||||
|
*/ |
||||||
|
public static class ImageDescriptor { //Struct
|
||||||
|
public ImageType type; |
||||||
|
public long width; |
||||||
|
public long height; |
||||||
|
public long depth; |
||||||
|
public long arraySize; |
||||||
|
public long rowPitch; |
||||||
|
public long slicePitch; |
||||||
|
public ByteBuffer hostPtr; |
||||||
|
/* |
||||||
|
public int numMipLevels; //They must always be set to zero
|
||||||
|
public int numSamples; |
||||||
|
*/ |
||||||
|
|
||||||
|
public ImageDescriptor() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used to specify an image with the provided ByteBuffer as soruce |
||||||
|
* @param type the image type |
||||||
|
* @param width the width |
||||||
|
* @param height the height, unused for image types {@code ImageType.IMAGE_1D*} |
||||||
|
* @param depth the depth of the image, only used for image type {@code ImageType.IMAGE_3D} |
||||||
|
* @param arraySize the number of array elements for image type {@code ImageType.IMAGE_1D_ARRAY} and {@code ImageType.IMAGE_2D_ARRAY} |
||||||
|
* @param rowPitch the row pitch of the provided buffer |
||||||
|
* @param slicePitch the slice pitch of the provided buffer |
||||||
|
* @param hostPtr host buffer used as image memory |
||||||
|
*/ |
||||||
|
public ImageDescriptor(ImageType type, long width, long height, long depth, long arraySize, long rowPitch, long slicePitch, ByteBuffer hostPtr) { |
||||||
|
this.type = type; |
||||||
|
this.width = width; |
||||||
|
this.height = height; |
||||||
|
this.depth = depth; |
||||||
|
this.arraySize = arraySize; |
||||||
|
this.rowPitch = rowPitch; |
||||||
|
this.slicePitch = slicePitch; |
||||||
|
this.hostPtr = hostPtr; |
||||||
|
} |
||||||
|
/** |
||||||
|
* Specifies an image without a host buffer, a new chunk of memory |
||||||
|
* will be allocated. |
||||||
|
* @param type the image type |
||||||
|
* @param width the width |
||||||
|
* @param height the height, unused for image types {@code ImageType.IMAGE_1D*} |
||||||
|
* @param depth the depth of the image, only used for image type {@code ImageType.IMAGE_3D} |
||||||
|
* @param arraySize the number of array elements for image type {@code ImageType.IMAGE_1D_ARRAY} and {@code ImageType.IMAGE_2D_ARRAY} |
||||||
|
*/ |
||||||
|
public ImageDescriptor(ImageType type, long width, long height, long depth, long arraySize) { |
||||||
|
this.type = type; |
||||||
|
this.width = width; |
||||||
|
this.height = height; |
||||||
|
this.depth = depth; |
||||||
|
this.arraySize = arraySize; |
||||||
|
this.rowPitch = 0; |
||||||
|
this.slicePitch = 0; |
||||||
|
hostPtr = null; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return "ImageDescriptor{" + "type=" + type + ", width=" + width + ", height=" + height + ", depth=" + depth + ", arraySize=" + arraySize + ", rowPitch=" + rowPitch + ", slicePitch=" + slicePitch + '}'; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
protected Image(ObjectReleaser releaser) { |
||||||
|
super(releaser); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the width of the image |
||||||
|
*/ |
||||||
|
public abstract long getWidth(); |
||||||
|
/** |
||||||
|
* @return the height of the image |
||||||
|
*/ |
||||||
|
public abstract long getHeight(); |
||||||
|
/** |
||||||
|
* @return the depth of the image |
||||||
|
*/ |
||||||
|
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) |
||||||
|
*/ |
||||||
|
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) |
||||||
|
*/ |
||||||
|
public abstract long getSlicePitch(); |
||||||
|
/** |
||||||
|
* @return the number of elements in the image array |
||||||
|
* @see ImageType#IMAGE_1D_ARRAY |
||||||
|
* @see ImageType#IMAGE_2D_ARRAY |
||||||
|
*/ |
||||||
|
public abstract long getArraySize(); |
||||||
|
/** |
||||||
|
* @return the image format |
||||||
|
*/ |
||||||
|
public abstract ImageFormat getImageFormat(); |
||||||
|
/** |
||||||
|
* @return the image type |
||||||
|
*/ |
||||||
|
public abstract ImageType getImageType(); |
||||||
|
/** |
||||||
|
* @return the number of bytes per pixel |
||||||
|
*/ |
||||||
|
public abstract int getElementSize(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs a blocking read of the image into the specified byte buffer. |
||||||
|
* @param queue the command queue |
||||||
|
* @param dest the target byte buffer |
||||||
|
* @param origin the image origin location, see class description for the format |
||||||
|
* @param region the copied region, see class description for the format |
||||||
|
* @param rowPitch the row pitch of the target buffer, must be set to 0 if the image is 1D. |
||||||
|
* If set to 0 for 2D and 3D image, the row pitch is calculated as {@code bytesPerElement * width} |
||||||
|
* @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} |
||||||
|
*/ |
||||||
|
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 |
||||||
|
* @param dest the target byte buffer |
||||||
|
* @param origin the image origin location, see class description for the format |
||||||
|
* @param region the copied region, see class description for the format |
||||||
|
* @param rowPitch the row pitch of the target buffer, must be set to 0 if the image is 1D. |
||||||
|
* If set to 0 for 2D and 3D image, the row pitch is calculated as {@code bytesPerElement * width} |
||||||
|
* @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} |
||||||
|
* @return the event object indicating the status of the operation |
||||||
|
*/ |
||||||
|
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. |
||||||
|
* @param queue the command queue |
||||||
|
* @param src the source buffer |
||||||
|
* @param origin the image origin location, see class description for the format |
||||||
|
* @param region the copied region, see class description for the format |
||||||
|
* @param rowPitch the row pitch of the target buffer, must be set to 0 if the image is 1D. |
||||||
|
* If set to 0 for 2D and 3D image, the row pitch is calculated as {@code bytesPerElement * width} |
||||||
|
* @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} |
||||||
|
*/ |
||||||
|
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 |
||||||
|
* @param src the source buffer |
||||||
|
* @param origin the image origin location, see class description for the format |
||||||
|
* @param region the copied region, see class description for the format |
||||||
|
* @param rowPitch the row pitch of the target buffer, must be set to 0 if the image is 1D. |
||||||
|
* If set to 0 for 2D and 3D image, the row pitch is calculated as {@code bytesPerElement * width} |
||||||
|
* @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} |
||||||
|
* @return the event object indicating the status of the operation |
||||||
|
*/ |
||||||
|
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. |
||||||
|
* <b>Important:</b> Both images must have the same format! |
||||||
|
* @param queue the command queue |
||||||
|
* @param dest the target image |
||||||
|
* @param srcOrigin the source image origin, see class description for the format |
||||||
|
* @param destOrigin the target image origin, see class description for the format |
||||||
|
* @param region the copied region, see class description for the format |
||||||
|
*/ |
||||||
|
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! |
||||||
|
* @param queue the command queue |
||||||
|
* @param dest the target image |
||||||
|
* @param srcOrigin the source image origin, see class description for the format |
||||||
|
* @param destOrigin the target image origin, see class description for the format |
||||||
|
* @param region the copied region, see class description for the format |
||||||
|
* @return the event object indicating the status of the operation |
||||||
|
*/ |
||||||
|
public abstract Event copyToAsync(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region); |
||||||
|
|
||||||
|
/** |
||||||
|
* Maps the image into host memory. |
||||||
|
* The returned structure contains the mapped byte buffer and row and slice pitch. |
||||||
|
* The event object is set to {@code null}, it is needed for the asnyc |
||||||
|
* version {@link #mapAsync(com.jme3.opencl.CommandQueue, long[], long[], com.jme3.opencl.MappingAccess) }. |
||||||
|
* @param queue the command queue |
||||||
|
* @param origin the image origin, see class description for the format |
||||||
|
* @param region the mapped region, see class description for the format |
||||||
|
* @param access the allowed memory access to the mapped memory |
||||||
|
* @return a structure describing the mapped memory |
||||||
|
* @see #unmap(com.jme3.opencl.CommandQueue, com.jme3.opencl.Image.ImageMapping) |
||||||
|
*/ |
||||||
|
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. |
||||||
|
* The event object is used to detect when the mapped memory is available. |
||||||
|
* @param queue the command queue |
||||||
|
* @param origin the image origin, see class description for the format |
||||||
|
* @param region the mapped region, see class description for the format |
||||||
|
* @param access the allowed memory access to the mapped memory |
||||||
|
* @return a structure describing the mapped memory |
||||||
|
* @see #unmap(com.jme3.opencl.CommandQueue, com.jme3.opencl.Image.ImageMapping) |
||||||
|
*/ |
||||||
|
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 |
||||||
|
*/ |
||||||
|
public abstract void unmap(CommandQueue queue, ImageMapping mapping); |
||||||
|
|
||||||
|
/** |
||||||
|
* Describes a mapped region of the image |
||||||
|
*/ |
||||||
|
public static class ImageMapping { |
||||||
|
/** |
||||||
|
* The raw byte buffer |
||||||
|
*/ |
||||||
|
public final ByteBuffer buffer; |
||||||
|
/** |
||||||
|
* The row pitch in bytes. |
||||||
|
* This value is at least {@code bytesPerElement * width} |
||||||
|
*/ |
||||||
|
public final long rowPitch; |
||||||
|
/** |
||||||
|
* The slice pitch in bytes. |
||||||
|
* This value is at least {@code rowPitch * height} |
||||||
|
*/ |
||||||
|
public final long slicePitch; |
||||||
|
/** |
||||||
|
* The event object used to detect when the memory is available. |
||||||
|
* @see #mapAsync(com.jme3.opencl.CommandQueue, long[], long[], com.jme3.opencl.MappingAccess) |
||||||
|
*/ |
||||||
|
public final Event event; |
||||||
|
|
||||||
|
public ImageMapping(ByteBuffer buffer, long rowPitch, long slicePitch, Event event) { |
||||||
|
this.buffer = buffer; |
||||||
|
this.rowPitch = rowPitch; |
||||||
|
this.slicePitch = slicePitch; |
||||||
|
this.event = event; |
||||||
|
} |
||||||
|
public ImageMapping(ByteBuffer buffer, long rowPitch, long slicePitch) { |
||||||
|
this.buffer = buffer; |
||||||
|
this.rowPitch = rowPitch; |
||||||
|
this.slicePitch = slicePitch; |
||||||
|
this.event = null; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Fills the image with the specified color. |
||||||
|
* Does <b>only</b> work if the image channel is {@link ImageChannelType#FLOAT} |
||||||
|
* or {@link ImageChannelType#HALF_FLOAT}. |
||||||
|
* @param queue the command queue |
||||||
|
* @param origin the image origin, see class description for the format |
||||||
|
* @param region the size of the region, see class description for the format |
||||||
|
* @param color the color to fill |
||||||
|
* @return an event object to detect for the completion |
||||||
|
*/ |
||||||
|
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} |
||||||
|
* or {@link ImageChannelType#HALF_FLOAT}. |
||||||
|
* @param queue the command queue |
||||||
|
* @param origin the image origin, see class description for the format |
||||||
|
* @param region the size of the region, see class description for the format |
||||||
|
* @param color the color to fill, must be an array of length 4 |
||||||
|
* @return an event object to detect for the completion |
||||||
|
*/ |
||||||
|
public abstract Event fillAsync(CommandQueue queue, long[] origin, long[] region, int[] color); |
||||||
|
|
||||||
|
/** |
||||||
|
* Copies this image into the specified buffer, no format conversion is done. |
||||||
|
* This is the dual function to |
||||||
|
* {@link Buffer#copyToImageAsync(com.jme3.opencl.CommandQueue, com.jme3.opencl.Image, long, long[], long[]) }. |
||||||
|
* @param queue the command queue |
||||||
|
* @param dest the target buffer |
||||||
|
* @param srcOrigin the image origin, see class description for the format |
||||||
|
* @param srcRegion the copied region, see class description for the format |
||||||
|
* @param destOffset an offset into the target buffer |
||||||
|
* @return the event object to detect the completion of the operation |
||||||
|
*/ |
||||||
|
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 |
||||||
|
* represents a shared object from OpenGL, created with e.g. |
||||||
|
* {@link Context#bindImage(com.jme3.texture.Image, com.jme3.texture.Texture.Type, int, com.jme3.opencl.MemoryAccess) } |
||||||
|
* or variations. |
||||||
|
* This method must be called before the image is used. After the work is |
||||||
|
* done, the image must be released by calling |
||||||
|
* {@link #releaseImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* so that OpenGL can use the image/texture/renderbuffer again. |
||||||
|
* @param queue the command queue |
||||||
|
* @return the event object |
||||||
|
*/ |
||||||
|
public abstract Event acquireImageForSharingAsync(CommandQueue queue); |
||||||
|
|
||||||
|
/** |
||||||
|
* Aquires this image object for using. Only call this method if this image |
||||||
|
* represents a shared object from OpenGL, created with e.g. |
||||||
|
* {@link Context#bindImage(com.jme3.texture.Image, com.jme3.texture.Texture.Type, int, com.jme3.opencl.MemoryAccess) } |
||||||
|
* or variations. |
||||||
|
* This method must be called before the image is used. After the work is |
||||||
|
* done, the image must be released by calling |
||||||
|
* {@link #releaseImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* so that OpenGL can use the image/texture/renderbuffer again. |
||||||
|
* |
||||||
|
* The generated event object is directly released. |
||||||
|
* This brings a performance improvement when the resource is e.g. directly |
||||||
|
* used by a kernel afterwards on the same queue (this implicitly waits for |
||||||
|
* this action). If you need the event, use |
||||||
|
* {@link #acquireImageForSharingAsync(com.jme3.opencl.CommandQueue) }. |
||||||
|
* |
||||||
|
* @param queue the command queue |
||||||
|
*/ |
||||||
|
public void acquireImageForSharingNoEvent(CommandQueue queue) { |
||||||
|
//Default implementation, overwrite for performance
|
||||||
|
acquireImageForSharingAsync(queue).release(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Releases a shared image object. |
||||||
|
* Call this method after the image object was acquired by |
||||||
|
* {@link #acquireImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* to hand the control back to OpenGL. |
||||||
|
* @param queue the command queue |
||||||
|
* @return the event object |
||||||
|
*/ |
||||||
|
public abstract Event releaseImageForSharingAsync(CommandQueue queue); |
||||||
|
|
||||||
|
/** |
||||||
|
* Releases a shared image object. |
||||||
|
* Call this method after the image object was acquired by |
||||||
|
* {@link #acquireImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* to hand the control back to OpenGL. |
||||||
|
* The generated event object is directly released, resulting in |
||||||
|
* performance improvements. |
||||||
|
* @param queue the command queue |
||||||
|
*/ |
||||||
|
public void releaseImageForSharingNoEvent(CommandQueue queue) { |
||||||
|
//default implementation, overwrite it for performance improvements
|
||||||
|
releaseImageForSharingAsync(queue).release(); |
||||||
|
} |
||||||
|
|
||||||
|
//TODO: add variants of the above two methods that don't create the event object, but release the event immediately
|
||||||
|
} |
@ -0,0 +1,628 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
import com.jme3.math.*; |
||||||
|
import com.jme3.util.TempVars; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.util.Arrays; |
||||||
|
|
||||||
|
/** |
||||||
|
* Wrapper for an OpenCL kernel, a piece of executable code on the GPU. |
||||||
|
* <p> |
||||||
|
* Terminology:<br> |
||||||
|
* A Kernel is executed in parallel. In total number of parallel threads, |
||||||
|
* called work items, are specified by the <i>global work size</i> (of type |
||||||
|
* {@link WorkSize}. These threads are organized in a 1D, 2D or 3D grid |
||||||
|
* (of coarse, this is only a logical view). Inside each kernel, |
||||||
|
* the id of each thread (i.e. the index inside this grid) can be requested |
||||||
|
* by {@code get_global_id(dimension)} with {@code dimension=0,1,2}. |
||||||
|
* <br> |
||||||
|
* Not all threads can always be executed in parallel because there simply might |
||||||
|
* not be enough processor cores. |
||||||
|
* Therefore, the concept of a <i>work group</i> is introduced. The work group |
||||||
|
* specifies the actual number of threads that are executed in parallel. |
||||||
|
* The maximal size of it can be queried by {@link Device#getMaxiumWorkItemsPerGroup() }. |
||||||
|
* Again, the threads inside the work group can be organized in a 1D, 2D or 3D |
||||||
|
* grid, but this is also just a logical view (specifying how the threads are |
||||||
|
* indexed). |
||||||
|
* The work group is imporatant for another concept: <i> shared memory</i> |
||||||
|
* Unlike the normal global or constant memory (passing a {@link Buffer} object |
||||||
|
* as argument), shared memory can't be set from outside. Shared memory is |
||||||
|
* allocated by the kernel and is only valid within the kernel. It is used |
||||||
|
* to quickly share data between threads within a work group. |
||||||
|
* The size of the shared memory is specified by setting an instance of |
||||||
|
* {@link LocalMem} or {@link LocalMemPerElement} as argument.<br> |
||||||
|
* Due to heavy register usage or other reasons, a kernel might not be able |
||||||
|
* to utilize a whole work group. Therefore, the actual number of threads |
||||||
|
* that can be executed in a work group can be queried by |
||||||
|
* {@link #getMaxWorkGroupSize(com.jme3.opencl.Device) }, which might differ from the |
||||||
|
* value returned from the Device. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* There are two ways to launch a kernel:<br> |
||||||
|
* First, arguments and the work group sizes can be set in advance |
||||||
|
* ({@code setArg(index, ...)}, {@code setGlobalWorkSize(...)} and {@code setWorkGroupSize(...)}. |
||||||
|
* Then a kernel is launched by {@link #Run(com.jme3.opencl.CommandQueue) }.<br> |
||||||
|
* Second, two convenient functions are provided that set the arguments |
||||||
|
* and work sizes in one call: |
||||||
|
* {@link #Run1(com.jme3.opencl.CommandQueue, com.jme3.opencl.Kernel.WorkSize, java.lang.Object...) } |
||||||
|
* and {@link #Run2(com.jme3.opencl.CommandQueue, com.jme3.opencl.Kernel.WorkSize, com.jme3.opencl.Kernel.WorkSize, java.lang.Object...) }. |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
* @see Program#createKernel(java.lang.String) |
||||||
|
*/ |
||||||
|
public abstract class Kernel extends AbstractOpenCLObject { |
||||||
|
/** |
||||||
|
* The current global work size |
||||||
|
*/ |
||||||
|
protected final WorkSize globalWorkSize; |
||||||
|
/** |
||||||
|
* The current local work size |
||||||
|
*/ |
||||||
|
protected final WorkSize workGroupSize; |
||||||
|
|
||||||
|
protected Kernel(ObjectReleaser releaser) { |
||||||
|
super(releaser); |
||||||
|
this.globalWorkSize = new WorkSize(0); |
||||||
|
this.workGroupSize = new WorkSize(0); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the name of the kernel as defined in the program source code |
||||||
|
*/ |
||||||
|
public abstract String getName(); |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the number of arguments |
||||||
|
*/ |
||||||
|
public abstract int getArgCount(); |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the current global work size |
||||||
|
*/ |
||||||
|
public WorkSize getGlobalWorkSize() { |
||||||
|
return globalWorkSize; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the global work size. |
||||||
|
* @param ws the work size to set |
||||||
|
*/ |
||||||
|
public void setGlobalWorkSize(WorkSize ws) { |
||||||
|
globalWorkSize.set(ws); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the global work size to a 1D grid |
||||||
|
* @param size the size in 1D |
||||||
|
*/ |
||||||
|
public void setGlobalWorkSize(int size) { |
||||||
|
globalWorkSize.set(1, size); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the global work size to be a 2D grid |
||||||
|
* @param width the width |
||||||
|
* @param height the height |
||||||
|
*/ |
||||||
|
public void setGlobalWorkSize(int width, int height) { |
||||||
|
globalWorkSize.set(2, width, height); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the global work size to be a 3D grid |
||||||
|
* @param width the width |
||||||
|
* @param height the height |
||||||
|
* @param depth the depth |
||||||
|
*/ |
||||||
|
public void setGlobalWorkSize(int width, int height, int depth) { |
||||||
|
globalWorkSize.set(3, width, height, depth); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the current work group size |
||||||
|
*/ |
||||||
|
public WorkSize getWorkGroupSize() { |
||||||
|
return workGroupSize; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the work group size |
||||||
|
* @param ws the work group size to set |
||||||
|
*/ |
||||||
|
public void setWorkGroupSize(WorkSize ws) { |
||||||
|
workGroupSize.set(ws); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the work group size to be a 1D grid |
||||||
|
* @param size the size to set |
||||||
|
*/ |
||||||
|
public void setWorkGroupSize(int size) { |
||||||
|
workGroupSize.set(1, size); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the work group size to be a 2D grid |
||||||
|
* @param width the width |
||||||
|
* @param height the height |
||||||
|
*/ |
||||||
|
public void setWorkGroupSize(int width, int height) { |
||||||
|
workGroupSize.set(2, width, height); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the work group size to be a 3D grid |
||||||
|
* @param width the width |
||||||
|
* @param height the height |
||||||
|
* @param depth the depth |
||||||
|
*/ |
||||||
|
public void setWorkGroupSdize(int width, int height, int depth) { |
||||||
|
workGroupSize.set(3, width, height, depth); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Tells the driver to figure out the work group size on their own. |
||||||
|
* Use this if you do not rely on specific work group layouts, i.e. |
||||||
|
* because shared memory is not used. |
||||||
|
* {@link #Run1(com.jme3.opencl.CommandQueue, com.jme3.opencl.Kernel.WorkSize, java.lang.Object...) } |
||||||
|
* implicetly calls this mehtod. |
||||||
|
*/ |
||||||
|
public void setWorkGroupSizeToNull() { |
||||||
|
workGroupSize.set(1, 0, 0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the maximal work group size when this kernel is executed on |
||||||
|
* the specified device |
||||||
|
* @param device the device |
||||||
|
* @return the maximal work group size |
||||||
|
*/ |
||||||
|
public abstract long getMaxWorkGroupSize(Device device); |
||||||
|
|
||||||
|
public abstract void setArg(int index, LocalMemPerElement t); |
||||||
|
|
||||||
|
public abstract void setArg(int index, LocalMem t); |
||||||
|
|
||||||
|
public abstract void setArg(int index, Buffer t); |
||||||
|
|
||||||
|
public abstract void setArg(int index, Image i); |
||||||
|
|
||||||
|
public abstract void setArg(int index, byte b); |
||||||
|
|
||||||
|
public abstract void setArg(int index, short s); |
||||||
|
|
||||||
|
public abstract void setArg(int index, int i); |
||||||
|
|
||||||
|
public abstract void setArg(int index, long l); |
||||||
|
|
||||||
|
public abstract void setArg(int index, float f); |
||||||
|
|
||||||
|
public abstract void setArg(int index, double d); |
||||||
|
|
||||||
|
public abstract void setArg(int index, Vector2f v); |
||||||
|
|
||||||
|
public abstract void setArg(int index, Vector4f v); |
||||||
|
|
||||||
|
public abstract void setArg(int index, Quaternion q); |
||||||
|
|
||||||
|
public abstract void setArg(int index, Matrix4f mat); |
||||||
|
|
||||||
|
public void setArg(int index, Matrix3f mat) { |
||||||
|
TempVars vars = TempVars.get(); |
||||||
|
try { |
||||||
|
Matrix4f m = vars.tempMat4; |
||||||
|
m.zero(); |
||||||
|
for (int i=0; i<3; ++i) { |
||||||
|
for (int j=0; j<3; ++j) { |
||||||
|
m.set(i, j, mat.get(i, j)); |
||||||
|
} |
||||||
|
} |
||||||
|
setArg(index, m); |
||||||
|
} finally { |
||||||
|
vars.release(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Raw version to set an argument. |
||||||
|
* {@code size} bytes of the provided byte buffer are copied to the kernel |
||||||
|
* argument. The size in bytes must match exactly the argument size |
||||||
|
* as defined in the kernel code. |
||||||
|
* Use this method to send custom structures to the kernel |
||||||
|
* @param index the index of the argument |
||||||
|
* @param buffer the raw buffer |
||||||
|
* @param size the size in bytes |
||||||
|
*/ |
||||||
|
public abstract void setArg(int index, ByteBuffer buffer, long size); |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the kernel argument at the specified index.<br> |
||||||
|
* The argument must be a known type: |
||||||
|
* {@code LocalMemPerElement, LocalMem, Image, Buffer, byte, short, int, |
||||||
|
* long, float, double, Vector2f, Vector4f, Quaternion, Matrix3f, Matrix4f}. |
||||||
|
* <br> |
||||||
|
* Note: Matrix3f and Matrix4f will be mapped to a {@code float16} (row major). |
||||||
|
* @param index the index of the argument, from 0 to {@link #getArgCount()}-1 |
||||||
|
* @param arg the argument |
||||||
|
* @throws IllegalArgumentException if the argument type is not one of the listed ones |
||||||
|
*/ |
||||||
|
public void setArg(int index, Object arg) { |
||||||
|
if (arg instanceof Byte) { |
||||||
|
setArg(index, (byte) arg); |
||||||
|
} else if (arg instanceof Short) { |
||||||
|
setArg(index, (short) arg); |
||||||
|
} else if (arg instanceof Integer) { |
||||||
|
setArg(index, (int) arg); |
||||||
|
} else if (arg instanceof Long) { |
||||||
|
setArg(index, (long) arg); |
||||||
|
} else if (arg instanceof Float) { |
||||||
|
setArg(index, (float) arg); |
||||||
|
} else if (arg instanceof Double) { |
||||||
|
setArg(index, (double) arg); |
||||||
|
} else if (arg instanceof Vector2f) { |
||||||
|
setArg(index, (Vector2f) arg); |
||||||
|
} else if (arg instanceof Vector4f) { |
||||||
|
setArg(index, (Vector4f) arg); |
||||||
|
} else if (arg instanceof Quaternion) { |
||||||
|
setArg(index, (Quaternion) arg); |
||||||
|
} else if (arg instanceof Matrix3f) { |
||||||
|
setArg(index, (Matrix3f) arg); |
||||||
|
} else if (arg instanceof Matrix4f) { |
||||||
|
setArg(index, (Matrix4f) arg); |
||||||
|
} else if (arg instanceof LocalMemPerElement) { |
||||||
|
setArg(index, (LocalMemPerElement) arg); |
||||||
|
} else if (arg instanceof LocalMem) { |
||||||
|
setArg(index, (LocalMem) arg); |
||||||
|
} else if (arg instanceof Buffer) { |
||||||
|
setArg(index, (Buffer) arg); |
||||||
|
} else if (arg instanceof Image) { |
||||||
|
setArg(index, (Image) arg); |
||||||
|
} else { |
||||||
|
throw new IllegalArgumentException("unknown kernel argument type: " + arg); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void setArgs(Object... args) { |
||||||
|
for (int i = 0; i < args.length; ++i) { |
||||||
|
setArg(i, args[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Launches the kernel with the current global work size, work group size |
||||||
|
* and arguments. |
||||||
|
* If the returned event object is not needed and would otherwise be |
||||||
|
* released immediately, {@link #RunNoEvent(com.jme3.opencl.CommandQueue) } |
||||||
|
* might bring a better performance. |
||||||
|
* @param queue the command queue |
||||||
|
* @return an event object indicating when the kernel is finished |
||||||
|
* @see #setGlobalWorkSize(com.jme3.opencl.Kernel.WorkSize) |
||||||
|
* @see #setWorkGroupSize(com.jme3.opencl.Kernel.WorkSize) |
||||||
|
* @see #setArg(int, java.lang.Object) |
||||||
|
*/ |
||||||
|
public abstract Event Run(CommandQueue queue); |
||||||
|
|
||||||
|
/** |
||||||
|
* Launches the kernel with the current global work size, work group size |
||||||
|
* and arguments without returning an event object. |
||||||
|
* The generated event is directly released. Therefore, the performance |
||||||
|
* is better, but there is no way to detect when the kernel execution |
||||||
|
* has finished. For this purpose, use {@link #Run(com.jme3.opencl.CommandQueue) }. |
||||||
|
* @param queue the command queue |
||||||
|
* @see #setGlobalWorkSize(com.jme3.opencl.Kernel.WorkSize) |
||||||
|
* @see #setWorkGroupSize(com.jme3.opencl.Kernel.WorkSize) |
||||||
|
* @see #setArg(int, java.lang.Object) |
||||||
|
*/ |
||||||
|
public void RunNoEvent(CommandQueue queue) { |
||||||
|
//Default implementation, overwrite to not allocate the event object
|
||||||
|
Run(queue).release(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the work sizes and arguments in one call and launches the kernel. |
||||||
|
* The global work size is set to the specified size. The work group |
||||||
|
* size is automatically determined by the driver. |
||||||
|
* Each object in the argument array is sent to the kernel by |
||||||
|
* {@link #setArg(int, java.lang.Object) }. |
||||||
|
* @param queue the command queue |
||||||
|
* @param globalWorkSize the global work size |
||||||
|
* @param args the kernel arguments |
||||||
|
* @return an event object indicating when the kernel is finished |
||||||
|
* @see #Run2(com.jme3.opencl.CommandQueue, com.jme3.opencl.Kernel.WorkSize, com.jme3.opencl.Kernel.WorkSize, java.lang.Object...) |
||||||
|
*/ |
||||||
|
public Event Run1(CommandQueue queue, WorkSize globalWorkSize, Object... args) { |
||||||
|
setGlobalWorkSize(globalWorkSize); |
||||||
|
setWorkGroupSizeToNull(); |
||||||
|
setArgs(args); |
||||||
|
return Run(queue); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the work sizes and arguments in one call and launches the kernel. |
||||||
|
* The global work size is set to the specified size. The work group |
||||||
|
* size is automatically determined by the driver. |
||||||
|
* Each object in the argument array is sent to the kernel by |
||||||
|
* {@link #setArg(int, java.lang.Object) }. |
||||||
|
* The generated event is directly released. Therefore, the performance |
||||||
|
* is better, but there is no way to detect when the kernel execution |
||||||
|
* has finished. For this purpose, use |
||||||
|
* {@link #Run1(com.jme3.opencl.CommandQueue, com.jme3.opencl.Kernel.WorkSize, java.lang.Object...) }. |
||||||
|
* @param queue the command queue |
||||||
|
* @param globalWorkSize the global work size |
||||||
|
* @param args the kernel arguments |
||||||
|
* @see #Run2(com.jme3.opencl.CommandQueue, com.jme3.opencl.Kernel.WorkSize, com.jme3.opencl.Kernel.WorkSize, java.lang.Object...) |
||||||
|
*/ |
||||||
|
public void Run1NoEvent(CommandQueue queue, WorkSize globalWorkSize, Object... args) { |
||||||
|
setGlobalWorkSize(globalWorkSize); |
||||||
|
setWorkGroupSizeToNull(); |
||||||
|
setArgs(args); |
||||||
|
RunNoEvent(queue); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the work sizes and arguments in one call and launches the kernel. |
||||||
|
* @param queue the command queue |
||||||
|
* @param globalWorkSize the global work size |
||||||
|
* @param workGroupSize the work group size |
||||||
|
* @param args the kernel arguments |
||||||
|
* @return an event object indicating when the kernel is finished |
||||||
|
*/ |
||||||
|
public Event Run2(CommandQueue queue, WorkSize globalWorkSize, |
||||||
|
WorkSize workGroupSize, Object... args) { |
||||||
|
setGlobalWorkSize(globalWorkSize); |
||||||
|
setWorkGroupSize(workGroupSize); |
||||||
|
setArgs(args); |
||||||
|
return Run(queue); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the work sizes and arguments in one call and launches the kernel. |
||||||
|
* The generated event is directly released. Therefore, the performance |
||||||
|
* is better, but there is no way to detect when the kernel execution |
||||||
|
* has finished. For this purpose, use |
||||||
|
* {@link #Run2(com.jme3.opencl.CommandQueue, com.jme3.opencl.Kernel.WorkSize, com.jme3.opencl.Kernel.WorkSize, java.lang.Object...) }. |
||||||
|
* @param queue the command queue |
||||||
|
* @param globalWorkSize the global work size |
||||||
|
* @param workGroupSize the work group size |
||||||
|
* @param args the kernel arguments |
||||||
|
*/ |
||||||
|
public void Run2NoEvent(CommandQueue queue, WorkSize globalWorkSize, |
||||||
|
WorkSize workGroupSize, Object... args) { |
||||||
|
setGlobalWorkSize(globalWorkSize); |
||||||
|
setWorkGroupSize(workGroupSize); |
||||||
|
setArgs(args); |
||||||
|
RunNoEvent(queue); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* A placeholder for kernel arguments representing local kernel memory. |
||||||
|
* This defines the size of available shared memory of a {@code __shared} kernel |
||||||
|
* argument |
||||||
|
*/ |
||||||
|
public static final class LocalMem { |
||||||
|
|
||||||
|
private int size; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new LocalMem instance |
||||||
|
* @param size the size of the available shared memory in bytes |
||||||
|
*/ |
||||||
|
public LocalMem(int size) { |
||||||
|
super(); |
||||||
|
this.size = size; |
||||||
|
} |
||||||
|
|
||||||
|
public int getSize() { |
||||||
|
return size; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int hashCode() { |
||||||
|
int hash = 3; |
||||||
|
hash = 79 * hash + this.size; |
||||||
|
return hash; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean equals(Object obj) { |
||||||
|
if (obj == null) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (getClass() != obj.getClass()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
final LocalMem other = (LocalMem) obj; |
||||||
|
if (this.size != other.size) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* A placeholder for a kernel argument representing local kernel memory per thread. |
||||||
|
* This effectively computes {@code SharedMemoryPerElement * WorkGroupSize} |
||||||
|
* and uses this value as the size of shared memory available in the kernel. |
||||||
|
* Therefore, an instance of this class must be set as an argument AFTER |
||||||
|
* the work group size has been specified. This is |
||||||
|
* ensured by {@link #Run2(com.jme3.opencl.CommandQueue, com.jme3.opencl.Kernel.WorkSize, com.jme3.opencl.Kernel.WorkSize, java.lang.Object...) }. |
||||||
|
* This argument can't be used when no work group size was defined explicetly |
||||||
|
* (e.g. by {@link #setWorkGroupSizeToNull()} or {@link #Run1(com.jme3.opencl.CommandQueue, com.jme3.opencl.Kernel.WorkSize, java.lang.Object...) }. |
||||||
|
*/ |
||||||
|
public static final class LocalMemPerElement { |
||||||
|
|
||||||
|
private int size; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new LocalMemPerElement instance |
||||||
|
* @param size the number of bytes available for each thread within |
||||||
|
* a work group |
||||||
|
*/ |
||||||
|
public LocalMemPerElement(int size) { |
||||||
|
super(); |
||||||
|
this.size = size; |
||||||
|
} |
||||||
|
|
||||||
|
public int getSize() { |
||||||
|
return size; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int hashCode() { |
||||||
|
int hash = 3; |
||||||
|
hash = 79 * hash + this.size; |
||||||
|
return hash; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean equals(Object obj) { |
||||||
|
if (obj == null) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (getClass() != obj.getClass()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
final LocalMemPerElement other = (LocalMemPerElement) obj; |
||||||
|
if (this.size != other.size) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* The work size (global and local) for executing a kernel |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public static final class WorkSize { |
||||||
|
|
||||||
|
private int dimension; |
||||||
|
private long[] sizes; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new work size object |
||||||
|
* @param dimension the dimension (1,2,3) |
||||||
|
* @param sizes the sizes in each dimension, the length must match the specified dimension |
||||||
|
*/ |
||||||
|
public WorkSize(int dimension, long... sizes) { |
||||||
|
super(); |
||||||
|
set(dimension, sizes); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a work size of dimension 1 and extend 1,1,1 (only one thread). |
||||||
|
*/ |
||||||
|
public WorkSize() { |
||||||
|
this(1, 1, 1, 1); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a 1D work size of the specified extend |
||||||
|
* @param size the size |
||||||
|
*/ |
||||||
|
public WorkSize(long size) { |
||||||
|
this(1, size, 1, 1); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a 2D work size of the specified extend |
||||||
|
* @param width the width |
||||||
|
* @param height the height |
||||||
|
*/ |
||||||
|
public WorkSize(long width, long height) { |
||||||
|
this(2, width, height, 1); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a 3D work size of the specified extend. |
||||||
|
* @param width the width |
||||||
|
* @param height the height |
||||||
|
* @param depth the depth |
||||||
|
*/ |
||||||
|
public WorkSize(long width, long height, long depth) { |
||||||
|
this(3, width, height, depth); |
||||||
|
} |
||||||
|
|
||||||
|
public int getDimension() { |
||||||
|
return dimension; |
||||||
|
} |
||||||
|
|
||||||
|
public long[] getSizes() { |
||||||
|
return sizes; |
||||||
|
} |
||||||
|
|
||||||
|
public void set(int dimension, long... sizes) { |
||||||
|
if (sizes == null || sizes.length != 3) { |
||||||
|
throw new IllegalArgumentException("sizes must be an array of length 3"); |
||||||
|
} |
||||||
|
if (dimension <= 0 || dimension > 3) { |
||||||
|
throw new IllegalArgumentException("dimension must be between 1 and 3"); |
||||||
|
} |
||||||
|
this.dimension = dimension; |
||||||
|
this.sizes = sizes; |
||||||
|
} |
||||||
|
|
||||||
|
public void set(WorkSize ws) { |
||||||
|
this.dimension = ws.dimension; |
||||||
|
this.sizes = ws.sizes; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int hashCode() { |
||||||
|
int hash = 5; |
||||||
|
hash = 47 * hash + this.dimension; |
||||||
|
hash = 47 * hash + Arrays.hashCode(this.sizes); |
||||||
|
return hash; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean equals(Object obj) { |
||||||
|
if (obj == null) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (getClass() != obj.getClass()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
final WorkSize other = (WorkSize) obj; |
||||||
|
if (this.dimension != other.dimension) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (!Arrays.equals(this.sizes, other.sizes)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
/** |
||||||
|
* This exception is thrown by {@link Program#build() } and {@link Program#build(java.lang.String) } |
||||||
|
* when the compilation failed. |
||||||
|
* The error log returned by {@link #getLog() } contains detailed information |
||||||
|
* where the error occured. |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class KernelCompilationException extends OpenCLException { |
||||||
|
|
||||||
|
private final String log; |
||||||
|
|
||||||
|
public KernelCompilationException(String msg, int errorCode, String log) { |
||||||
|
super(msg, errorCode); |
||||||
|
this.log = log; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* The output of the compiler |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public String getLog() { |
||||||
|
return log; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
/** |
||||||
|
* Specifies the access flags when mapping a {@link Buffer} or {@link Image} object. |
||||||
|
* @see Buffer#map(com.jme3.opencl.CommandQueue, long, long, com.jme3.opencl.MappingAccess) |
||||||
|
* @see Image#map(com.jme3.opencl.CommandQueue, long[], long[], com.jme3.opencl.MappingAccess) |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public enum MappingAccess { |
||||||
|
/** |
||||||
|
* Only read access is allowed to the mapped memory. |
||||||
|
*/ |
||||||
|
MAP_READ_ONLY, |
||||||
|
/** |
||||||
|
* Only write access is allowed to the mapped memory. |
||||||
|
*/ |
||||||
|
MAP_WRITE_ONLY, |
||||||
|
/** |
||||||
|
* Both read and write access is allowed. |
||||||
|
*/ |
||||||
|
MAP_READ_WRITE, |
||||||
|
/** |
||||||
|
* The old memory content is completely discarded and the buffer is filled |
||||||
|
* completely with new data. This might be faster than {@link #MAP_WRITE_ONLY} |
||||||
|
*/ |
||||||
|
MAP_WRITE_INVALIDATE |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
/** |
||||||
|
* Specifies how a buffer object can be accessed by the kernel. |
||||||
|
* @author shaman |
||||||
|
* @see Buffer |
||||||
|
*/ |
||||||
|
public enum MemoryAccess { |
||||||
|
/** |
||||||
|
* A kernel can both read and write the buffer. |
||||||
|
*/ |
||||||
|
READ_WRITE, |
||||||
|
/** |
||||||
|
* A kernel can only write this buffer. |
||||||
|
*/ |
||||||
|
WRITE_ONLY, |
||||||
|
/** |
||||||
|
* A kernel can only read this buffer |
||||||
|
*/ |
||||||
|
READ_ONLY |
||||||
|
} |
@ -0,0 +1,78 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
/** |
||||||
|
* Generic OpenCL exception, can be thrown in every method of this package. |
||||||
|
* The error code and its name is reported in the message string as well as the OpenCL call that |
||||||
|
* causes this exception. Please refer to the official OpenCL specification |
||||||
|
* to see what might cause this exception. |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class OpenCLException extends RuntimeException { |
||||||
|
private static final long serialVersionUID = 8471229972153694848L; |
||||||
|
|
||||||
|
private final int errorCode; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new instance of <code>OpenCLExceptionn</code> without detail |
||||||
|
* message. |
||||||
|
*/ |
||||||
|
public OpenCLException() { |
||||||
|
errorCode = 0; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructs an instance of <code>OpenCLExceptionn</code> with the |
||||||
|
* specified detail message. |
||||||
|
* |
||||||
|
* @param msg the detail message. |
||||||
|
*/ |
||||||
|
public OpenCLException(String msg) { |
||||||
|
super(msg); |
||||||
|
errorCode = 0; |
||||||
|
} |
||||||
|
|
||||||
|
public OpenCLException(String msg, int errorCode) { |
||||||
|
super(msg); |
||||||
|
this.errorCode = errorCode; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the error code |
||||||
|
*/ |
||||||
|
public int getErrorCode() { |
||||||
|
return errorCode; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,75 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
/** |
||||||
|
* 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(); |
||||||
|
} |
@ -0,0 +1,123 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
import java.lang.ref.PhantomReference; |
||||||
|
import java.lang.ref.ReferenceQueue; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
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; |
||||||
|
/** |
||||||
|
* Call Runtime.getRuntime().gc() every these frames |
||||||
|
*/ |
||||||
|
private static final int GC_FREQUENCY = 10; |
||||||
|
|
||||||
|
private static final OpenCLObjectManager INSTANCE = new OpenCLObjectManager(); |
||||||
|
private OpenCLObjectManager() {} |
||||||
|
|
||||||
|
public static OpenCLObjectManager getInstance() { |
||||||
|
return INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
private ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>(); |
||||||
|
private HashSet<OpenCLObjectRef> activeObjects = new HashSet<OpenCLObjectRef>(); |
||||||
|
private int gcCounter = 0; |
||||||
|
|
||||||
|
private static class OpenCLObjectRef extends PhantomReference<Object> { |
||||||
|
|
||||||
|
private OpenCLObject.ObjectReleaser releaser; |
||||||
|
|
||||||
|
public OpenCLObjectRef(ReferenceQueue<Object> refQueue, OpenCLObject obj){ |
||||||
|
super(obj, refQueue); |
||||||
|
releaser = obj.getReleaser(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void registerObject(OpenCLObject obj) { |
||||||
|
OpenCLObjectRef ref = new OpenCLObjectRef(refQueue, obj); |
||||||
|
activeObjects.add(ref); |
||||||
|
LOG.log(LOG_LEVEL1, "registered OpenCL object: {0}", obj); |
||||||
|
} |
||||||
|
|
||||||
|
private void deleteObject(OpenCLObjectRef ref) { |
||||||
|
LOG.log(LOG_LEVEL1, "deleting OpenCL object by: {0}", ref.releaser); |
||||||
|
ref.releaser.release(); |
||||||
|
activeObjects.remove(ref); |
||||||
|
} |
||||||
|
|
||||||
|
public void deleteUnusedObjects() { |
||||||
|
if (activeObjects.isEmpty()) { |
||||||
|
LOG.log(LOG_LEVEL2, "no active natives"); |
||||||
|
return; //nothing to do
|
||||||
|
} |
||||||
|
|
||||||
|
gcCounter++; |
||||||
|
if (gcCounter >= GC_FREQUENCY) { |
||||||
|
//The program is that the OpenCLObjects are so small that they are
|
||||||
|
//enqueued for finalization very late. Therefore, without this
|
||||||
|
//hack, we are running out of host memory on the OpenCL side quickly.
|
||||||
|
gcCounter = 0; |
||||||
|
Runtime.getRuntime().gc(); |
||||||
|
} |
||||||
|
|
||||||
|
int removed = 0; |
||||||
|
while (true) { |
||||||
|
// Remove objects reclaimed by GC.
|
||||||
|
OpenCLObjectRef ref = (OpenCLObjectRef) refQueue.poll(); |
||||||
|
if (ref == null) { |
||||||
|
break; |
||||||
|
} |
||||||
|
deleteObject(ref); |
||||||
|
removed++; |
||||||
|
} |
||||||
|
if (removed >= 1) { |
||||||
|
LOG.log(LOG_LEVEL2, "{0} native objects were removed from native", removed); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void deleteAllObjects() { |
||||||
|
for (OpenCLObjectRef ref : activeObjects) { |
||||||
|
LOG.log(LOG_LEVEL1, "deleting OpenCL object by: {0}", ref.releaser); |
||||||
|
ref.releaser.release(); |
||||||
|
} |
||||||
|
activeObjects.clear(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
import java.util.Collection; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* A wrapper for an OpenCL platform. A platform is the highest object in the |
||||||
|
* object hierarchy, it creates the {@link Device}s which are then used to |
||||||
|
* create the {@link Context}.<br> |
||||||
|
* This class is mostly used within {@link PlatformChooser}. |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public interface Platform { |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the list of available devices for this platform |
||||||
|
*/ |
||||||
|
List<? extends Device> getDevices(); |
||||||
|
|
||||||
|
/** |
||||||
|
* @return The profile string |
||||||
|
*/ |
||||||
|
String getProfile(); |
||||||
|
/** |
||||||
|
* @return {@code true} if this platform implements the full profile |
||||||
|
*/ |
||||||
|
boolean isFullProfile(); |
||||||
|
/** |
||||||
|
* @return {@code true} if this platform implements the embedded profile |
||||||
|
*/ |
||||||
|
boolean isEmbeddedProfile(); |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the version string |
||||||
|
*/ |
||||||
|
String getVersion(); |
||||||
|
/** |
||||||
|
* Extracts the major version from the version string |
||||||
|
* @return the major version |
||||||
|
*/ |
||||||
|
int getVersionMajor(); |
||||||
|
/** |
||||||
|
* Extracts the minor version from the version string |
||||||
|
* @return the minor version |
||||||
|
*/ |
||||||
|
int getVersionMinor(); |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the name of the platform |
||||||
|
*/ |
||||||
|
String getName(); |
||||||
|
/** |
||||||
|
* @return the vendor of the platform |
||||||
|
*/ |
||||||
|
String getVendor(); |
||||||
|
/** |
||||||
|
* Queries if this platform supports OpenGL interop at all. |
||||||
|
* This value has also to be tested for every device. |
||||||
|
* @return {@code true} if OpenGL interop is supported |
||||||
|
*/ |
||||||
|
boolean hasOpenGLInterop(); |
||||||
|
/** |
||||||
|
* Queries if the specified extension is available. |
||||||
|
* This value has to be tested also for every device. |
||||||
|
* @param extension the extension string |
||||||
|
* @return {@code true} if this extension is supported by the platform |
||||||
|
* (however, not all devices might support it as well) |
||||||
|
*/ |
||||||
|
boolean hasExtension(String extension); |
||||||
|
/** |
||||||
|
* @return All available extensions |
||||||
|
*/ |
||||||
|
Collection<? extends String> getExtensions(); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
import com.jme3.system.AppSettings; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* This SPI is called on startup to specify which platform and which devices |
||||||
|
* are used for context creation. |
||||||
|
* @author shaman |
||||||
|
* @see AppSettings#setOpenCLPlatformChooser(java.lang.Class) |
||||||
|
*/ |
||||||
|
public interface PlatformChooser { |
||||||
|
|
||||||
|
/** |
||||||
|
* Chooses one or more devices for the opencl context. |
||||||
|
* All returned devices must belong to the same platform. |
||||||
|
* If the returned list is empty, no context will be created. |
||||||
|
* @param platforms the available platforms |
||||||
|
* @return the list of devices |
||||||
|
*/ |
||||||
|
List<? extends Device> chooseDevices(List<? extends Platform> platforms); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,104 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
import java.nio.ByteBuffer; |
||||||
|
|
||||||
|
/** |
||||||
|
* A wrapper for an OpenCL program. A program is created from kernel source code, |
||||||
|
* manages the build process and creates the kernels. |
||||||
|
* <p> |
||||||
|
* Warning: Creating the same kernel more than one leads to undefined behaviour, |
||||||
|
* this is especially important for {@link #createAllKernels() } |
||||||
|
* |
||||||
|
* @see Context#createProgramFromSourceCode(java.lang.String) |
||||||
|
* @see #createKernel(java.lang.String) |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public abstract class Program extends AbstractOpenCLObject { |
||||||
|
|
||||||
|
protected Program(ObjectReleaser releaser) { |
||||||
|
super(releaser); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Builds this program with the specified argument string on the specified |
||||||
|
* devices. |
||||||
|
* Please see the official OpenCL specification for a definition of |
||||||
|
* all supported arguments. |
||||||
|
* The list of devices specify on which device the compiled program |
||||||
|
* can then be executed. It must be a subset of {@link Context#getDevices() }. |
||||||
|
* If {@code null} is passed, the program is built on all available devices. |
||||||
|
* |
||||||
|
* @param args the compilation arguments |
||||||
|
* @param devices a list of devices on which the program is build. |
||||||
|
* @throws KernelCompilationException if the compilation fails |
||||||
|
* @see #build() |
||||||
|
*/ |
||||||
|
public abstract void build(String args, Device... devices) throws KernelCompilationException; |
||||||
|
/** |
||||||
|
* Builds this program without additional arguments |
||||||
|
* @throws KernelCompilationException if the compilation fails |
||||||
|
* @see #build(java.lang.String) |
||||||
|
*/ |
||||||
|
public void build() throws KernelCompilationException { |
||||||
|
build("", (Device[]) null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates the kernel with the specified name. |
||||||
|
* @param name the name of the kernel as defined in the source code |
||||||
|
* @return the kernel object |
||||||
|
* @throws OpenCLException if the kernel was not found or some other |
||||||
|
* error occured |
||||||
|
*/ |
||||||
|
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 |
||||||
|
*/ |
||||||
|
public abstract Kernel[] createAllKernels(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Queries a compiled binary representation of this program for a particular |
||||||
|
* device. This binary can then be used e.g. in the next application launch |
||||||
|
* to create the program from the binaries and not from the sources. |
||||||
|
* This saves time. |
||||||
|
* @param device the device from which the binaries are taken |
||||||
|
* @return the binaries |
||||||
|
* @see Context#createProgramFromBinary(java.nio.ByteBuffer, com.jme3.opencl.Device) |
||||||
|
*/ |
||||||
|
public abstract ByteBuffer getBinary(Device device); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,229 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
|
||||||
|
import com.jme3.system.JmeSystem; |
||||||
|
import com.jme3.util.BufferUtils; |
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.nio.file.Files; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* Implements a simple cache system for program objects. |
||||||
|
* The program objects are saved persistently with {@link #saveToCache(java.lang.String, com.jme3.opencl.Program) }. |
||||||
|
* On the next run, the stored programs can then be loaded |
||||||
|
* with {@link #loadFromCache(java.lang.String, java.lang.String) }. |
||||||
|
* <br> |
||||||
|
* The programs are identified by a unique id. The following format is recommended: |
||||||
|
* {@code id = <full name of the class using the program>.<unique identifier within that class>}. |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class ProgramCache { |
||||||
|
private static final Logger LOG = Logger.getLogger(ProgramCache.class.getName()); |
||||||
|
private static final String FILE_EXTENSION = ".clbin"; |
||||||
|
|
||||||
|
private final Context context; |
||||||
|
private final Device device; |
||||||
|
private final File tmpFolder; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a "disabled" program cache, no caching is done. |
||||||
|
* {@link #loadFromCache(java.lang.String) } will always return {@code null} |
||||||
|
* and {@link #saveToCache(java.lang.String, com.jme3.opencl.Program) } does |
||||||
|
* nothing.<br> |
||||||
|
* Use this during development if you still modify your kernel code. |
||||||
|
* (Otherwise, you don't see the changes because you are still use the |
||||||
|
* cached version of your program) |
||||||
|
*/ |
||||||
|
public ProgramCache() { |
||||||
|
this.context = null; |
||||||
|
this.device = null; |
||||||
|
this.tmpFolder = null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new program cache associated with the specified context and |
||||||
|
* devices. |
||||||
|
* The cached programs are built against the specified device and also |
||||||
|
* only the binaries linked to that device are stored. |
||||||
|
* @param context the OpenCL context |
||||||
|
* @param device the OpenCL device |
||||||
|
*/ |
||||||
|
public ProgramCache(Context context, Device device) { |
||||||
|
this.context = context; |
||||||
|
this.device = device; |
||||||
|
if (JmeSystem.isLowPermissions()) { |
||||||
|
tmpFolder = null; |
||||||
|
} else { |
||||||
|
tmpFolder = JmeSystem.getStorageFolder(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected String getCleanFileName(String id) { |
||||||
|
//http://stackoverflow.com/a/35591188/4053176
|
||||||
|
return id.replaceAll("[^a-zA-Z0-9.-]", "") + FILE_EXTENSION; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new program cache using the first device from the specified |
||||||
|
* context. |
||||||
|
* @param context the context |
||||||
|
* @see #ProgramCache(com.jme3.opencl.Context, com.jme3.opencl.Device) |
||||||
|
*/ |
||||||
|
public ProgramCache(Context context) { |
||||||
|
this(context, context.getDevices().get(0)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Loads the program from the cache and builds it against the current device. |
||||||
|
* You can pass additional build arguments with the parameter {@code buildArgs}. |
||||||
|
* <p> |
||||||
|
* The cached program is identified by the specified id. |
||||||
|
* This id must be unique, otherwise collisions within the cache occur. |
||||||
|
* Therefore, the following naming schema is recommended: |
||||||
|
* {@code id = <full name of the class using the program>.<unique identifier within that class>}. |
||||||
|
* <p> |
||||||
|
* If the program can't be loaded, built or any other exception happened, |
||||||
|
* {@code null} is returned. |
||||||
|
* |
||||||
|
* @param id the unique identifier of this program |
||||||
|
* @param buildArgs additional build arguments, can be {@code null} |
||||||
|
* @return the loaded and built program, or {@code null} |
||||||
|
* @see #saveToCache(java.lang.String, com.jme3.opencl.Program) |
||||||
|
*/ |
||||||
|
public Program loadFromCache(String id, String buildArgs) { |
||||||
|
if (tmpFolder == null) { |
||||||
|
return null; //low permissions
|
||||||
|
} |
||||||
|
//get file
|
||||||
|
File file = new File(tmpFolder, getCleanFileName(id)); |
||||||
|
if (!file.exists()) { |
||||||
|
if (LOG.isLoggable(Level.FINE)) { |
||||||
|
LOG.log(Level.FINE, "Cache file {0} does not exist", file.getAbsolutePath()); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
//load from file
|
||||||
|
ByteBuffer bb; |
||||||
|
try { |
||||||
|
byte[] bytes = Files.readAllBytes(file.toPath()); |
||||||
|
bb = BufferUtils.createByteBuffer(bytes); |
||||||
|
} catch (IOException ex) { |
||||||
|
LOG.log(Level.FINE, "Unable to read cache file", ex); |
||||||
|
return null; |
||||||
|
} |
||||||
|
//create program
|
||||||
|
Program program; |
||||||
|
try { |
||||||
|
program = context.createProgramFromBinary(bb, device); |
||||||
|
} catch (OpenCLException ex) { |
||||||
|
LOG.log(Level.FINE, "Unable to create program from binary", ex); |
||||||
|
return null; |
||||||
|
} |
||||||
|
//build program
|
||||||
|
try { |
||||||
|
program.build(buildArgs, device); |
||||||
|
} catch (OpenCLException ex) { |
||||||
|
LOG.log(Level.FINE, "Unable to build program", ex); |
||||||
|
return null; |
||||||
|
} |
||||||
|
//done
|
||||||
|
return program; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Calls {@link #loadFromCache(java.lang.String, java.lang.String) } |
||||||
|
* with the additional build arguments set to {@code ""}. |
||||||
|
* @param id a unique identifier of the program |
||||||
|
* @return the loaded and built program or {@code null} if this |
||||||
|
* program could not be loaded from the cache |
||||||
|
* @see #loadFromCache(java.lang.String, java.lang.String) |
||||||
|
*/ |
||||||
|
public Program loadFromCache(String id) { |
||||||
|
return loadFromCache(id, ""); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Saves the specified program in the cache. |
||||||
|
* The parameter {@code id} denotes the name of the program. Under this id, |
||||||
|
* the program is then loaded again by {@link #loadFromCache(java.lang.String, java.lang.String) }. |
||||||
|
* <br> |
||||||
|
* The id must be unique, otherwise collisions within the cache occur. |
||||||
|
* Therefore, the following naming schema is recommended: |
||||||
|
* {@code id = <full name of the class using the program>.<unique identifier within that class>}. |
||||||
|
* |
||||||
|
* @param id the program id |
||||||
|
* @param program the program to store in the cache |
||||||
|
*/ |
||||||
|
public void saveToCache(String id, Program program) { |
||||||
|
if (tmpFolder == null) { |
||||||
|
return; //low permissions
|
||||||
|
} |
||||||
|
//get file
|
||||||
|
File file = new File(tmpFolder, getCleanFileName(id)); |
||||||
|
//get binaries
|
||||||
|
ByteBuffer bb; |
||||||
|
try { |
||||||
|
bb = program.getBinary(device); |
||||||
|
} catch (UnsupportedOperationException | OpenCLException ex) { |
||||||
|
LOG.log(Level.WARNING, "Unable to retrieve the program binaries", ex); |
||||||
|
return; |
||||||
|
} |
||||||
|
byte[] bytes = new byte[bb.remaining()]; |
||||||
|
bb.get(bytes); |
||||||
|
//save
|
||||||
|
try { |
||||||
|
Files.write(file.toPath(), bytes); |
||||||
|
} catch (IOException ex) { |
||||||
|
LOG.log(Level.WARNING, "Unable to save program binaries to the cache", ex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Clears the cache. |
||||||
|
* All saved program binaries are deleted. |
||||||
|
*/ |
||||||
|
public void clearCache() { |
||||||
|
if (tmpFolder == null) { |
||||||
|
return; //low permissions
|
||||||
|
} |
||||||
|
for (File file : tmpFolder.listFiles()) { |
||||||
|
if (file.isFile() && file.getName().endsWith(FILE_EXTENSION)) { |
||||||
|
file.delete(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,163 @@ |
|||||||
|
/* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* This package contains an API for using OpenCL together with jME3. |
||||||
|
* <p> |
||||||
|
* <b>Activation:</b><br> |
||||||
|
* OpenCL is deactivated by default. To activate it, set {@link com.jme3.system.AppSettings#setOpenCLSupport(boolean) } |
||||||
|
* to {@code true}. |
||||||
|
* If the current platform supports OpenCL, then the central {@link com.jme3.opencl.Context} |
||||||
|
* can be fetched by {@link com.jme3.system.JmeContext#getOpenCLContext() } which is |
||||||
|
* available in each application. If OpenCL is deactivated or not available, |
||||||
|
* this method returns {@code null}. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* <b>First steps:</b><br> |
||||||
|
* Once you have obtained your {@link com.jme3.opencl.Context} you start by |
||||||
|
* creating a {@link com.jme3.opencl.CommandQueue} by calling |
||||||
|
* {@link com.jme3.opencl.Context#createQueue() } or alternative versions. |
||||||
|
* The command queue must be passed to every following method that execute |
||||||
|
* some action involving the GPU. All actions are executed in the order in which they |
||||||
|
* are added to the queue. |
||||||
|
* <br> |
||||||
|
* <b>Programs and Kernels:</b> |
||||||
|
* The main purpose of OpenCL is to execute code in parallel |
||||||
|
* on the GPU. From the source code, a {@link com.jme3.opencl.Program} object |
||||||
|
* is created by {@link com.jme3.opencl.Context#createProgramFromSourceCode(java.lang.String) }, |
||||||
|
* {@link com.jme3.opencl.Context#createProgramFromSourceFilesWithInclude(com.jme3.asset.AssetManager, java.lang.String, java.util.List) } |
||||||
|
* or alternative versions. |
||||||
|
* Before using it, the source code must be build using {@link com.jme3.opencl.Program#build() }. |
||||||
|
* Any compilation error is thrown here. Each program consists of multiple kernels. |
||||||
|
* Each kernel represents one executable unit and is declared in the source code |
||||||
|
* with the following syntax: {@code __kernel void KernelName(KernelArgs) {Code} }. |
||||||
|
* On the programming side, a {@link com.jme3.opencl.Kernel} instance is obtained |
||||||
|
* by calling {@link com.jme3.opencl.Program#createKernel(java.lang.String) }. |
||||||
|
* To execute the kernel, the method {@link com.jme3.opencl.Kernel#Run1(com.jme3.opencl.CommandQueue, com.jme3.opencl.WorkSize, java.lang.Object...) } |
||||||
|
* is provided. You first pass the command queue and the work size (i.e. the number of parallel executed threads) |
||||||
|
* followed by the kernel arguments. |
||||||
|
* <br> |
||||||
|
* <b>Buffers and Images:</b> |
||||||
|
* OpenCL Kernels show their true power first when they operate on buffers and images. |
||||||
|
* Buffers are simple one dimensional consecutive chunks of memory of arbitrary size. |
||||||
|
* These {@link com.jme3.opencl.Buffer} instances are created by calling |
||||||
|
* {@link com.jme3.opencl.Context#createBuffer(long)} with the size in bytes as |
||||||
|
* the argument. A buffer on its own is typeless. In the kernel, you then specify |
||||||
|
* the type of the buffer by argument declarations like {@code __global float* buffer}. |
||||||
|
* Note that OpenCL does not check buffer boundaries. If you read or write outside |
||||||
|
* of the buffer, the behavior is completely undefined and may often result in |
||||||
|
* a program cache later on. |
||||||
|
* {@link com.jme3.opencl.Image} objects are structured one, two or three dimensional |
||||||
|
* memory chunks of a fixed type. They are created by |
||||||
|
* {@link com.jme3.opencl.Context#createImage(com.jme3.opencl.MemoryAccess, com.jme3.opencl.Image.ImageFormat, com.jme3.opencl.Image.ImageDescriptor, java.nio.ByteBuffer) }. |
||||||
|
* They need special functions in the kernel code to write to or read from images. |
||||||
|
* Both buffer and image objects provide methods for copying between buffers and images, |
||||||
|
* reading and writing to host code and directly mapping memory parts to the host code. |
||||||
|
* <br> |
||||||
|
* <b>Events:</b> |
||||||
|
* Most methods are provided in two variations: blocking calls or asynchronous |
||||||
|
* calls (the later one have the suffix -Async, or all kernel calls). |
||||||
|
* These async calls all return {@link com.jme3.opencl.Event} objects. |
||||||
|
* These events can be used to check (non-blocking) if the action has completed, e.g. a memory copy |
||||||
|
* is finished, or to block the execution until the action has finished. |
||||||
|
* <br> |
||||||
|
* Some methods have the suffix {@code -NoEvent}. This means that these methods |
||||||
|
* don't return an event object even if the OpenCL function would return an event. |
||||||
|
* There exists always an alternative version that does return an event. |
||||||
|
* These methods exist to increase the performance: since all actions (like multiple kernel calls) |
||||||
|
* that are sent to the same command queue are executed in order, there is no |
||||||
|
* need for intermediate events. (These intermediate events would be released |
||||||
|
* immediately). Therefore, the no-event alternatives increase the performance |
||||||
|
* because no additional event object has to be allocated and less system calls |
||||||
|
* are neccessary. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* <b>Interoperability between OpenCL and jME3:</b><br> |
||||||
|
* This Wrapper allows to share jME3 Images and VertexBuffers with OpenCL.<br> |
||||||
|
* {@link com.jme3.scene.VertexBuffer} objects can be shared with OpenCL |
||||||
|
* by calling {@link com.jme3.opencl.Context#bindVertexBuffer(com.jme3.scene.VertexBuffer, com.jme3.opencl.MemoryAccess) } |
||||||
|
* resulting in a {@link com.jme3.opencl.Buffer} object. This buffer object |
||||||
|
* can then be used as usual, allowing e.g. the dynamic modification of position buffers for particle systems.<br> |
||||||
|
* {@link com.jme3.texture.Image} and {@link com.jme3.texture.Texture} objects can be used in OpenCL with the method |
||||||
|
* {@link com.jme3.opencl.Context#bindImage(com.jme3.texture.Texture, com.jme3.opencl.MemoryAccess) } |
||||||
|
* or variations of this method. The same holds for {@link com.jme3.texture.FrameBuffer.RenderBuffer} objects |
||||||
|
* using {@link com.jme3.opencl.Context#bindRenderBuffer(com.jme3.texture.FrameBuffer.RenderBuffer, com.jme3.opencl.MemoryAccess) }. |
||||||
|
* These methods result in an OpenCL-Image. Usages are e.g. animated textures, |
||||||
|
* terrain based on height maps, post processing effects and so forth. |
||||||
|
* <br> |
||||||
|
* <i>Important:</i> Before shared objects can be used by any OpenCL function |
||||||
|
* like kernel calls or read/write/copy methods, they must be aquired explicitly |
||||||
|
* by {@link com.jme3.opencl.Buffer#acquireBufferForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* or {@link com.jme3.opencl.Image#acquireImageForSharingAsync(com.jme3.opencl.CommandQueue) }. |
||||||
|
* After the work is done, release the resource with |
||||||
|
* {@link com.jme3.opencl.Buffer#releaseBufferForSharingAsync(com.jme3.opencl.CommandQueue) } |
||||||
|
* or {@link com.jme3.opencl.Image#releaseImageForSharingAsync(com.jme3.opencl.CommandQueue) }. |
||||||
|
* This ensures the synchronization of OpenCL and OpenGL. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* <b>Experts: choosing the right platform and devices</b><br> |
||||||
|
* OpenCL can run on different platforms and different devices. On some systems, |
||||||
|
* like multi-GPU setups, this choice really matters. To specify which platform |
||||||
|
* and which devices are used, a custom implementation of |
||||||
|
* {@link com.jme3.opencl.PlatformChooser} can be used by calling |
||||||
|
* {@link com.jme3.system.AppSettings#setOpenCLPlatformChooser(java.lang.Class) }. |
||||||
|
* For more details, see the documentation of {@code PlatformChooser}. |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* <b>Exception handling:</b><br> |
||||||
|
* All OpenCL-wrapper classes in this package
|
||||||
|
* (this includes {@link com.jme3.opencl.Platform}, {@link com.jme3.opencl.Device}, |
||||||
|
* {@link com.jme3.opencl.Context}, {@link com.jme3.opencl.CommandQueue}, |
||||||
|
* {@link com.jme3.opencl.Buffer}, {@link com.jme3.opencl.Image}, |
||||||
|
* {@link com.jme3.opencl.Program}, {@link com.jme3.opencl.Kernel} and |
||||||
|
* {@link com.jme3.opencl.Event}) |
||||||
|
* may throw the following exceptions in each method without being mentioned |
||||||
|
* explicetly in the documentation: |
||||||
|
* <ul> |
||||||
|
* <li>{@code NullPointerException}: one of the arguments is {@code null} and |
||||||
|
* {@code null} is not allowed</li> |
||||||
|
* <li>{@code IllegalArgumentException}: the arguments don't follow the rules |
||||||
|
* as specified in the documentation of the method, e.g. values are out of range |
||||||
|
* or an array has the wrong size</li> |
||||||
|
* <li>{@link com.jme3.opencl.OpenCLException}: some low-level exception was |
||||||
|
* thrown. The exception always records the error code and error name and the |
||||||
|
* OpenCL function call where the error was detected. Please check the official |
||||||
|
* OpenCL specification for the meanings of these errors for that particular function.</li> |
||||||
|
* <li>{@code UnsupportedOperationException}: the OpenCL implementation does not |
||||||
|
* support some operations. This is currently only an issue for Jogamp's Jogl |
||||||
|
* renderer, since Jocl only supports OpenCL 1.1. LWJGL has full support for |
||||||
|
* OpenCL 1.2 and 2.0. |
||||||
|
* </ul> |
||||||
|
*/ |
||||||
|
package com.jme3.opencl; |
||||||
|
|
||||||
|
//TODO: add profiling to Kernel, CommandQueue
|
@ -0,0 +1,224 @@ |
|||||||
|
|
||||||
|
#ifndef MATRIX3_H |
||||||
|
#define MATRIX3_H |
||||||
|
|
||||||
|
//Simple matrix library. |
||||||
|
//A 3x3 matrix is represented as a float16 in row major order |
||||||
|
|
||||||
|
typedef float16 mat3; |
||||||
|
|
||||||
|
//All matrix functions are prefixed with mat3 or mat4 |
||||||
|
|
||||||
|
//Returns the zero matrix |
||||||
|
inline mat3 mat3Zero() { |
||||||
|
return (float16)(0); |
||||||
|
} |
||||||
|
|
||||||
|
//Returns the identity matrix |
||||||
|
inline mat3 mat3Identity() { |
||||||
|
return (float16) |
||||||
|
(1, 0, 0, 0, |
||||||
|
0, 1, 0, 0, |
||||||
|
0, 0, 1, 0, |
||||||
|
0, 0, 0, 1); |
||||||
|
} |
||||||
|
|
||||||
|
inline mat3 mat3FromRows(float3 row1, float3 row2, float3 row3) { |
||||||
|
return (float16) |
||||||
|
(row1.x, row1.y, row1.z, 0, |
||||||
|
row2.x, row2.y, row2.z, 0, |
||||||
|
row3.x, row3.y, row3.z, 0, |
||||||
|
0, 0, 0, 1); |
||||||
|
} |
||||||
|
|
||||||
|
inline mat3 mat3FromColumns(float3 col1, float3 col2, float3 col3) { |
||||||
|
return (float16) |
||||||
|
(col1.x, col2.x, col3.x, 0, |
||||||
|
col1.y, col2.y, col3.y, 0, |
||||||
|
col1.z, col2.z, col3.z, 0, |
||||||
|
0, 0, 0, 1); |
||||||
|
} |
||||||
|
|
||||||
|
inline mat3 mat3FromDiagonal(float3 diag) { |
||||||
|
return (float16) |
||||||
|
(diag.x, 0, 0, 0, |
||||||
|
0, diag.y, 0, 0, |
||||||
|
0, 0, diag.z, 0, |
||||||
|
0, 0, 0, 1); |
||||||
|
} |
||||||
|
|
||||||
|
//Returns the i-th row (0-based) |
||||||
|
inline float3 mat3GetRow(mat3 mat, int i) { |
||||||
|
if (i==0) return mat.s012; |
||||||
|
else if (i==1) return mat.s456; |
||||||
|
else return mat.s89a; |
||||||
|
} |
||||||
|
|
||||||
|
//Sets the i-th row (0-based) |
||||||
|
inline mat3 mat3SetRow(mat3 mat, int i, float3 row) { |
||||||
|
if (i==0) mat.s012 = row; |
||||||
|
else if (i==1) mat.s456 = row; |
||||||
|
else mat.s89a = row; |
||||||
|
return mat; |
||||||
|
} |
||||||
|
|
||||||
|
//Returns the i-th column (0-based) |
||||||
|
inline float3 mat3GetColumn(mat3 mat, int i) { |
||||||
|
if (i==0) return mat.s048; |
||||||
|
else if (i==1) return mat.s159; |
||||||
|
else return mat.s26a; |
||||||
|
} |
||||||
|
|
||||||
|
//Sets the i-th column (0-based) |
||||||
|
inline mat3 mat3SetColumn(mat3 mat, int i, float3 col) { |
||||||
|
if (i==0) mat.s048 = col; |
||||||
|
else if (i==1) mat.s159 = col; |
||||||
|
else mat.s26a = col; |
||||||
|
return mat; |
||||||
|
} |
||||||
|
|
||||||
|
//Returns the diagonal |
||||||
|
inline float3 mat3GetDiagonal(mat3 mat) { |
||||||
|
return mat.s05a; |
||||||
|
} |
||||||
|
|
||||||
|
//Sets the diagonal |
||||||
|
inline mat3 mat3SetDiagonal(mat3 mat, float3 diag) { |
||||||
|
mat.s05a = diag; |
||||||
|
return mat; |
||||||
|
} |
||||||
|
|
||||||
|
mat3 mat3FromAngleNormalAxis(float angle, float3 axis) { |
||||||
|
float fCos = cos(angle); |
||||||
|
float fSin = sin(angle); |
||||||
|
float fOneMinusCos = 1.0f - fCos; |
||||||
|
float fX2 = axis.x * axis.x; |
||||||
|
float fY2 = axis.y * axis.y; |
||||||
|
float fZ2 = axis.z * axis.z; |
||||||
|
float fXYM = axis.x * axis.y * fOneMinusCos; |
||||||
|
float fXZM = axis.x * axis.z * fOneMinusCos; |
||||||
|
float fYZM = axis.y * axis.z * fOneMinusCos; |
||||||
|
float fXSin = axis.x * fSin; |
||||||
|
float fYSin = axis.y * fSin; |
||||||
|
float fZSin = axis.z * fSin; |
||||||
|
|
||||||
|
return (float16) ( |
||||||
|
fX2 * fOneMinusCos + fCos, |
||||||
|
fXYM - fZSin, |
||||||
|
fXZM + fYSin, |
||||||
|
0, |
||||||
|
fXYM + fZSin, |
||||||
|
fY2 * fOneMinusCos + fCos, |
||||||
|
fYZM - fXSin, |
||||||
|
0, |
||||||
|
fXZM - fYSin, |
||||||
|
fYZM + fXSin, |
||||||
|
fZ2 * fOneMinusCos + fCos, |
||||||
|
0, |
||||||
|
0, 0, 0, 1 |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
mat3 mat3FromAngleAxis(float angle, float3 axis) { |
||||||
|
return mat3FromAngleNormalAxis(angle, normalize(axis)); |
||||||
|
} |
||||||
|
|
||||||
|
//Multiplies the two matrices A and B |
||||||
|
inline mat3 mat3Mult(mat3 A, mat3 B) { |
||||||
|
return (float16) ( |
||||||
|
dot(A.s012, B.s048), |
||||||
|
dot(A.s012, B.s159), |
||||||
|
dot(A.s012, B.s26a), |
||||||
|
0, |
||||||
|
dot(A.s456, B.s048), |
||||||
|
dot(A.s456, B.s159), |
||||||
|
dot(A.s456, B.s26a), |
||||||
|
0, |
||||||
|
dot(A.s89a, B.s048), |
||||||
|
dot(A.s89a, B.s159), |
||||||
|
dot(A.s89a, B.s26a), |
||||||
|
0, |
||||||
|
0, 0, 0, 1 |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
//Computes Av (right multiply of a vector to a matrix) |
||||||
|
inline float3 mat3VMult(mat3 A, float3 v) { |
||||||
|
return (float3) ( |
||||||
|
dot(A.s012, v), |
||||||
|
dot(A.s456, v), |
||||||
|
dot(A.s89a, v)); |
||||||
|
} |
||||||
|
|
||||||
|
//Computes vA (left multiply of a vector to a matrix) |
||||||
|
inline float3 mat3VMult2(float3 v, mat3 A) { |
||||||
|
return (float3) ( |
||||||
|
dot(v, A.s048), |
||||||
|
dot(v, A.s159), |
||||||
|
dot(v, A.s26a)); |
||||||
|
} |
||||||
|
|
||||||
|
//Scales this matrix by a constant |
||||||
|
inline mat3 mat3Scale(mat3 mat, float s) { |
||||||
|
return s*mat; |
||||||
|
} |
||||||
|
|
||||||
|
//Transposes this matrix |
||||||
|
inline mat3 mat3Transpose(mat3 mat) { |
||||||
|
return mat.s048c159d26ae37bf; //magic |
||||||
|
} |
||||||
|
|
||||||
|
//Computes the determinant |
||||||
|
inline float mat3Determinant(mat3 mat) { |
||||||
|
float fCo00 = mat.s5 * mat.sa - mat.s6 * mat.s9; |
||||||
|
float fCo10 = mat.s6 * mat.s8 - mat.s4 * mat.sa; |
||||||
|
float fCo20 = mat.s4 * mat.s9 - mat.s5 * mat.s8; |
||||||
|
float fDet = mat.s0 * fCo00 + mat.s1 * fCo10 + mat.s2 * fCo20; |
||||||
|
return fDet; |
||||||
|
} |
||||||
|
|
||||||
|
//Creates the adjoint |
||||||
|
inline mat3 mat3Adjoint(mat3 mat) { |
||||||
|
return (float16) ( |
||||||
|
mat.s5 * mat.sa - mat.s6 * mat.s9, |
||||||
|
mat.s2 * mat.s9 - mat.s1 * mat.sa, |
||||||
|
mat.s1 * mat.s6 - mat.s2 * mat.s5, |
||||||
|
0, |
||||||
|
mat.s6 * mat.s8 - mat.s4 * mat.sa, |
||||||
|
mat.s0 * mat.sa - mat.s2 * mat.s8, |
||||||
|
mat.s2 * mat.s4 - mat.s0 * mat.s6, |
||||||
|
0, |
||||||
|
mat.s4 * mat.s9 - mat.s5 * mat.s8, |
||||||
|
mat.s1 * mat.s8 - mat.s0 * mat.s9, |
||||||
|
mat.s0 * mat.s5 - mat.s1 * mat.s4, |
||||||
|
0, |
||||||
|
0, 0, 0, 1 |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
//Inverts this matrix |
||||||
|
inline mat3 mat3Invert(mat3 mat) { |
||||||
|
float det = mat3Determinant(mat); |
||||||
|
if (fabs(det) <= 1.1920928955078125E-7f) return mat3Zero(); |
||||||
|
mat3 m = mat3Adjoint(mat); |
||||||
|
return m / det; |
||||||
|
} |
||||||
|
|
||||||
|
//Computes A+B |
||||||
|
inline mat3 mat3Add(mat3 A, mat3 B) { |
||||||
|
return A + B; |
||||||
|
} |
||||||
|
|
||||||
|
inline bool mat3Equals(mat3 A, mat3 B, float epsilon) { |
||||||
|
return fabs(A.s0 - B.s0)<epsilon |
||||||
|
&& fabs(A.s1 - B.s1)<epsilon |
||||||
|
&& fabs(A.s2 - B.s2)<epsilon |
||||||
|
&& fabs(A.s4 - B.s4)<epsilon |
||||||
|
&& fabs(A.s5 - B.s5)<epsilon |
||||||
|
&& fabs(A.s6 - B.s6)<epsilon |
||||||
|
&& fabs(A.s8 - B.s8)<epsilon |
||||||
|
&& fabs(A.s9 - B.s9)<epsilon |
||||||
|
&& fabs(A.sa - B.sa)<epsilon; |
||||||
|
} |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,319 @@ |
|||||||
|
|
||||||
|
#ifndef MATRIX4_H |
||||||
|
#define MATRIX4_H |
||||||
|
|
||||||
|
//Simple matrix library. |
||||||
|
//A 4x4 matrix is represented as a float16 in row major order |
||||||
|
|
||||||
|
typedef float16 mat4; |
||||||
|
|
||||||
|
//All matrix functions are prefixed with mat3 or mat4 |
||||||
|
|
||||||
|
//Returns the zero matrix |
||||||
|
inline mat4 mat4Zero() { |
||||||
|
return (float16)(0); |
||||||
|
} |
||||||
|
|
||||||
|
//Returns the identity matrix |
||||||
|
inline mat4 mat4Identity() { |
||||||
|
return (float16) |
||||||
|
(1, 0, 0, 0, |
||||||
|
0, 1, 0, 0, |
||||||
|
0, 0, 1, 0, |
||||||
|
0, 0, 0, 1); |
||||||
|
} |
||||||
|
|
||||||
|
inline mat4 mat4FromRows(float4 row1, float4 row2, float4 row3, float4 row4) { |
||||||
|
return (float16) (row1, row2, row3, row4); |
||||||
|
} |
||||||
|
|
||||||
|
inline mat4 mat4FromColumns(float4 col1, float4 col2, float4 col3, float4 col4) { |
||||||
|
return (float16) |
||||||
|
(col1.x, col2.x, col3.x, col4.x, |
||||||
|
col1.y, col2.y, col3.y, col4.y, |
||||||
|
col1.z, col2.z, col3.z, col4.z, |
||||||
|
col1.w, col2.w, col3.w, col4.w); |
||||||
|
} |
||||||
|
|
||||||
|
inline mat4 mat4FromDiagonal(float4 diag) { |
||||||
|
return (float16) |
||||||
|
(diag.x, 0, 0, 0, |
||||||
|
0, diag.y, 0, 0, |
||||||
|
0, 0, diag.z, 0, |
||||||
|
0, 0, 0, diag.w); |
||||||
|
} |
||||||
|
|
||||||
|
//Returns the i-th row (0-based) |
||||||
|
inline float4 mat4GetRow(mat4 mat, int i) { |
||||||
|
if (i==0) return mat.s0123; |
||||||
|
else if (i==1) return mat.s4567; |
||||||
|
else if (i==2) return mat.s89ab; |
||||||
|
else return mat.scdef; |
||||||
|
} |
||||||
|
|
||||||
|
//Sets the i-th row (0-based) |
||||||
|
inline mat4 mat4SetRow(mat4 mat, int i, float4 row) { |
||||||
|
if (i==0) mat.s0123 = row; |
||||||
|
else if (i==1) mat.s4567 = row; |
||||||
|
else if (i==2) mat.s89ab = row; |
||||||
|
else mat.scdef = row; |
||||||
|
return mat; |
||||||
|
} |
||||||
|
|
||||||
|
//Returns the i-th column (0-based) |
||||||
|
inline float4 mat4GetColumn(mat4 mat, int i) { |
||||||
|
if (i==0) return mat.s048c; |
||||||
|
else if (i==1) return mat.s159d; |
||||||
|
else if (i==2) return mat.s26ae; |
||||||
|
else return mat.s37bf; |
||||||
|
} |
||||||
|
|
||||||
|
//Sets the i-th column (0-based) |
||||||
|
inline mat4 mat4SetColumn(mat4 mat, int i, float4 col) { |
||||||
|
if (i==0) mat.s048c = col; |
||||||
|
else if (i==1) mat.s159d = col; |
||||||
|
else if (i==2) mat.s26ae = col; |
||||||
|
else mat.s37bf = col; |
||||||
|
return mat; |
||||||
|
} |
||||||
|
|
||||||
|
//Returns the diagonal |
||||||
|
inline float4 mat4GetDiagonal(mat4 mat) { |
||||||
|
return mat.s05af; |
||||||
|
} |
||||||
|
|
||||||
|
//Sets the diagonal |
||||||
|
inline mat4 mat3SetDiagonal(mat4 mat, float4 diag) { |
||||||
|
mat.s05af = diag; |
||||||
|
return mat; |
||||||
|
} |
||||||
|
|
||||||
|
mat4 mat4FromFrame(float3 location, float3 direction, float3 up, float3 left) |
||||||
|
{ |
||||||
|
float3 fwdVector = direction; |
||||||
|
float3 leftVector = cross(fwdVector, up); |
||||||
|
float3 upVector = cross(leftVector, fwdVector); |
||||||
|
|
||||||
|
return (float16) ( |
||||||
|
leftVector.x, |
||||||
|
leftVector.y, |
||||||
|
leftVector.z, |
||||||
|
dot(-leftVector, location), |
||||||
|
|
||||||
|
upVector.x, |
||||||
|
upVector.y, |
||||||
|
upVector.z, |
||||||
|
dot(-upVector, location), |
||||||
|
|
||||||
|
-fwdVector.x, |
||||||
|
-fwdVector.y, |
||||||
|
-fwdVector.z, |
||||||
|
dot(fwdVector, location), |
||||||
|
|
||||||
|
0, 0, 0, 1 |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
inline mat4 mat4Transpose(mat4 mat) { |
||||||
|
return mat.s048c159d26ae37bf; //magic |
||||||
|
} |
||||||
|
|
||||||
|
mat4 mat4FromAngleNormalAxis(float angle, float3 axis) { |
||||||
|
float fCos = cos(angle); |
||||||
|
float fSin = sin(angle); |
||||||
|
float fOneMinusCos = 1.0f - fCos; |
||||||
|
float fX2 = axis.x * axis.x; |
||||||
|
float fY2 = axis.y * axis.y; |
||||||
|
float fZ2 = axis.z * axis.z; |
||||||
|
float fXYM = axis.x * axis.y * fOneMinusCos; |
||||||
|
float fXZM = axis.x * axis.z * fOneMinusCos; |
||||||
|
float fYZM = axis.y * axis.z * fOneMinusCos; |
||||||
|
float fXSin = axis.x * fSin; |
||||||
|
float fYSin = axis.y * fSin; |
||||||
|
float fZSin = axis.z * fSin; |
||||||
|
|
||||||
|
return (float16) ( |
||||||
|
fX2 * fOneMinusCos + fCos, |
||||||
|
fXYM - fZSin, |
||||||
|
fXZM + fYSin, |
||||||
|
0, |
||||||
|
fXYM + fZSin, |
||||||
|
fY2 * fOneMinusCos + fCos, |
||||||
|
fYZM - fXSin, |
||||||
|
0, |
||||||
|
fXZM - fYSin, |
||||||
|
fYZM + fXSin, |
||||||
|
fZ2 * fOneMinusCos + fCos, |
||||||
|
0, |
||||||
|
0, 0, 0, 1 |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
mat4 mat4FromAngleAxis(float angle, float3 axis) { |
||||||
|
return mat4FromAngleNormalAxis(angle, normalize(axis)); |
||||||
|
} |
||||||
|
|
||||||
|
inline mat4 mat4Scale(mat4 mat, float s) { |
||||||
|
return mat * s; |
||||||
|
} |
||||||
|
|
||||||
|
inline mat4 mat4Add(mat4 A, mat4 B) { |
||||||
|
return A + B; |
||||||
|
} |
||||||
|
|
||||||
|
//Multiplies the two matrices A and B |
||||||
|
inline mat4 mat4Mult(mat4 A, mat4 B) { |
||||||
|
return (float16) ( |
||||||
|
dot(A.s0123, B.s048c), |
||||||
|
dot(A.s0123, B.s159d), |
||||||
|
dot(A.s0123, B.s26ae), |
||||||
|
dot(A.s0123, B.s37bf), |
||||||
|
|
||||||
|
dot(A.s4567, B.s048c), |
||||||
|
dot(A.s4567, B.s159d), |
||||||
|
dot(A.s4567, B.s26ae), |
||||||
|
dot(A.s4567, B.s37bf), |
||||||
|
|
||||||
|
dot(A.s89ab, B.s048c), |
||||||
|
dot(A.s89ab, B.s159d), |
||||||
|
dot(A.s89ab, B.s26ae), |
||||||
|
dot(A.s89ab, B.s37bf), |
||||||
|
|
||||||
|
dot(A.scdef, B.s048c), |
||||||
|
dot(A.scdef, B.s159d), |
||||||
|
dot(A.scdef, B.s26ae), |
||||||
|
dot(A.scdef, B.s37bf) |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
//Computes Av (right multiply of a vector to a matrix) |
||||||
|
inline float4 mat4VMult(mat4 A, float4 v) { |
||||||
|
return (float4) ( |
||||||
|
dot(A.s0123, v), |
||||||
|
dot(A.s4567, v), |
||||||
|
dot(A.s89ab, v), |
||||||
|
dot(A.scdef, v)); |
||||||
|
} |
||||||
|
|
||||||
|
//Computes vA (left multiply of a vector to a matrix) |
||||||
|
inline float4 mat4VMult2(float4 v, mat4 A) { |
||||||
|
return (float4) ( |
||||||
|
dot(v, A.s048c), |
||||||
|
dot(v, A.s159d), |
||||||
|
dot(v, A.s26ae), |
||||||
|
dot(v, A.s37bf)); |
||||||
|
} |
||||||
|
|
||||||
|
inline float4 mat4MultAcross(mat4 mat, float4 v) { |
||||||
|
return mat4VMult2(v, mat); |
||||||
|
} |
||||||
|
|
||||||
|
inline float3 mat4MultNormal(mat4 mat, float3 v) { |
||||||
|
return mat4VMult(mat, (float4)(v, 0)).xyz; |
||||||
|
} |
||||||
|
|
||||||
|
inline float3 mat4MultNormalAcross(mat4 mat, float3 v) { |
||||||
|
return mat4VMult2((float4)(v, 0), mat).xyz; |
||||||
|
} |
||||||
|
|
||||||
|
mat4 mat4Invert(mat4 mat) { |
||||||
|
float fA0 = mat.s0 * mat.s5 - mat.s1 * mat.s4; |
||||||
|
float fA1 = mat.s0 * mat.s6 - mat.s2 * mat.s4; |
||||||
|
float fA2 = mat.s0 * mat.s7 - mat.s3 * mat.s4; |
||||||
|
float fA3 = mat.s1 * mat.s6 - mat.s2 * mat.s5; |
||||||
|
float fA4 = mat.s1 * mat.s7 - mat.s3 * mat.s5; |
||||||
|
float fA5 = mat.s2 * mat.s7 - mat.s3 * mat.s6; |
||||||
|
float fB0 = mat.s8 * mat.sd - mat.s9 * mat.sc; |
||||||
|
float fB1 = mat.s8 * mat.se - mat.sa * mat.sc; |
||||||
|
float fB2 = mat.s8 * mat.sf - mat.sb * mat.sc; |
||||||
|
float fB3 = mat.s9 * mat.se - mat.sa * mat.sd; |
||||||
|
float fB4 = mat.s9 * mat.sf - mat.sb * mat.sd; |
||||||
|
float fB5 = mat.sa * mat.sf - mat.sb * mat.se; |
||||||
|
float fDet = fA0 * fB5 - fA1 * fB4 + fA2 * fB3 + fA3 * fB2 - fA4 * fB1 + fA5 * fB0; |
||||||
|
|
||||||
|
if (fabs(fDet) <= 0.000001f) { |
||||||
|
return mat4Zero(); |
||||||
|
} |
||||||
|
|
||||||
|
mat4 store; |
||||||
|
store.s0 = +mat.s5 * fB5 - mat.s6 * fB4 + mat.s7 * fB3; |
||||||
|
store.s4 = -mat.s4 * fB5 + mat.s6 * fB2 - mat.s7 * fB1; |
||||||
|
store.s8 = +mat.s4 * fB4 - mat.s5 * fB2 + mat.s7 * fB0; |
||||||
|
store.sc = -mat.s4 * fB3 + mat.s5 * fB1 - mat.s6 * fB0; |
||||||
|
store.s1 = -mat.s1 * fB5 + mat.s2 * fB4 - mat.s3 * fB3; |
||||||
|
store.s5 = +mat.s0 * fB5 - mat.s2 * fB2 + mat.s3 * fB1; |
||||||
|
store.s9 = -mat.s0 * fB4 + mat.s1 * fB2 - mat.s3 * fB0; |
||||||
|
store.sd = +mat.s0 * fB3 - mat.s1 * fB1 + mat.s2 * fB0; |
||||||
|
store.s2 = +mat.sd * fA5 - mat.se * fA4 + mat.sf * fA3; |
||||||
|
store.s6 = -mat.sc * fA5 + mat.se * fA2 - mat.sf * fA1; |
||||||
|
store.sa = +mat.sc * fA4 - mat.sd * fA2 + mat.sf * fA0; |
||||||
|
store.se = -mat.sc * fA3 + mat.sd * fA1 - mat.se * fA0; |
||||||
|
store.s3 = -mat.s9 * fA5 + mat.sa * fA4 - mat.sb * fA3; |
||||||
|
store.s7 = +mat.s8 * fA5 - mat.sa * fA2 + mat.sb * fA1; |
||||||
|
store.sb = -mat.s8 * fA4 + mat.s9 * fA2 - mat.sb * fA0; |
||||||
|
store.sf = +mat.s8 * fA3 - mat.s9 * fA1 + mat.sa * fA0; |
||||||
|
|
||||||
|
store /= fDet; |
||||||
|
|
||||||
|
return store; |
||||||
|
} |
||||||
|
|
||||||
|
mat4 mat4Adjoint(mat4 mat) { |
||||||
|
float fA0 = mat.s0 * mat.s5 - mat.s1 * mat.s4; |
||||||
|
float fA1 = mat.s0 * mat.s6 - mat.s2 * mat.s4; |
||||||
|
float fA2 = mat.s0 * mat.s7 - mat.s3 * mat.s4; |
||||||
|
float fA3 = mat.s1 * mat.s6 - mat.s2 * mat.s5; |
||||||
|
float fA4 = mat.s1 * mat.s7 - mat.s3 * mat.s5; |
||||||
|
float fA5 = mat.s2 * mat.s7 - mat.s3 * mat.s6; |
||||||
|
float fB0 = mat.s8 * mat.sd - mat.s9 * mat.sc; |
||||||
|
float fB1 = mat.s8 * mat.se - mat.sa * mat.sc; |
||||||
|
float fB2 = mat.s8 * mat.sf - mat.sb * mat.sc; |
||||||
|
float fB3 = mat.s9 * mat.se - mat.sa * mat.sd; |
||||||
|
float fB4 = mat.s9 * mat.sf - mat.sb * mat.sd; |
||||||
|
float fB5 = mat.sa * mat.sf - mat.sb * mat.se; |
||||||
|
|
||||||
|
mat4 store; |
||||||
|
|
||||||
|
store.s0 = +mat.s5 * fB5 - mat.s6 * fB4 + mat.s7 * fB3; |
||||||
|
store.s4 = -mat.s4 * fB5 + mat.s6 * fB2 - mat.s7 * fB1; |
||||||
|
store.s8 = +mat.s4 * fB4 - mat.s5 * fB2 + mat.s7 * fB0; |
||||||
|
store.sc = -mat.s4 * fB3 + mat.s5 * fB1 - mat.s6 * fB0; |
||||||
|
store.s1 = -mat.s1 * fB5 + mat.s2 * fB4 - mat.s3 * fB3; |
||||||
|
store.s5 = +mat.s0 * fB5 - mat.s2 * fB2 + mat.s3 * fB1; |
||||||
|
store.s9 = -mat.s0 * fB4 + mat.s1 * fB2 - mat.s3 * fB0; |
||||||
|
store.sd = +mat.s0 * fB3 - mat.s1 * fB1 + mat.s2 * fB0; |
||||||
|
store.s2 = +mat.sd * fA5 - mat.se * fA4 + mat.sf * fA3; |
||||||
|
store.s6 = -mat.sc * fA5 + mat.se * fA2 - mat.sf * fA1; |
||||||
|
store.sa = +mat.sc * fA4 - mat.sd * fA2 + mat.sf * fA0; |
||||||
|
store.se = -mat.sc * fA3 + mat.sd * fA1 - mat.se * fA0; |
||||||
|
store.s3 = -mat.s9 * fA5 + mat.sa * fA4 - mat.sb * fA3; |
||||||
|
store.s7 = +mat.s8 * fA5 - mat.sa * fA2 + mat.sb * fA1; |
||||||
|
store.sb = -mat.s8 * fA4 + mat.s9 * fA2 - mat.sb * fA0; |
||||||
|
store.sf = +mat.s8 * fA3 - mat.s9 * fA1 + mat.sa * fA0; |
||||||
|
|
||||||
|
return store; |
||||||
|
} |
||||||
|
|
||||||
|
float mat4Determinant(mat4 mat) { |
||||||
|
float fA0 = mat.s0 * mat.s5 - mat.s1 * mat.s4; |
||||||
|
float fA1 = mat.s0 * mat.s6 - mat.s2 * mat.s4; |
||||||
|
float fA2 = mat.s0 * mat.s7 - mat.s3 * mat.s4; |
||||||
|
float fA3 = mat.s1 * mat.s6 - mat.s2 * mat.s5; |
||||||
|
float fA4 = mat.s1 * mat.s7 - mat.s3 * mat.s5; |
||||||
|
float fA5 = mat.s2 * mat.s7 - mat.s3 * mat.s6; |
||||||
|
float fB0 = mat.s8 * mat.sd - mat.s9 * mat.sc; |
||||||
|
float fB1 = mat.s8 * mat.se - mat.sa * mat.sc; |
||||||
|
float fB2 = mat.s8 * mat.sf - mat.sb * mat.sc; |
||||||
|
float fB3 = mat.s9 * mat.se - mat.sa * mat.sd; |
||||||
|
float fB4 = mat.s9 * mat.sf - mat.sb * mat.sd; |
||||||
|
float fB5 = mat.sa * mat.sf - mat.sb * mat.se; |
||||||
|
float fDet = fA0 * fB5 - fA1 * fB4 + fA2 * fB3 + fA3 * fB2 - fA4 * fB1 + fA5 * fB0; |
||||||
|
return fDet; |
||||||
|
} |
||||||
|
|
||||||
|
inline bool mat4Equals(mat4 A, mat4 B, float epsilon) { |
||||||
|
return all(isless(fabs(A - B), epsilon)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,185 @@ |
|||||||
|
//This is a port of java.util.Random to OpenCL |
||||||
|
|
||||||
|
//Because not all devices support doubles, the double returning functions |
||||||
|
//must be explicit activated with the following preprocessor macro: |
||||||
|
//#define RANDOM_DOUBLES |
||||||
|
|
||||||
|
#ifdef RANDOM_DOUBLES |
||||||
|
//#ifdef cl_khr_fp64 |
||||||
|
#pragma OPENCL EXTENSION cl_khr_fp64 : enable |
||||||
|
//#elif defined(cl_amd_fp64) |
||||||
|
//#pragma OPENCL EXTENSION cl_amd_fp64 : enable |
||||||
|
//#else |
||||||
|
//#error "Double precision floating point not supported by OpenCL implementation." |
||||||
|
//#endif |
||||||
|
#endif |
||||||
|
|
||||||
|
inline int randNext(int bits, __global ulong* seed) |
||||||
|
{ |
||||||
|
*seed = (*seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1); |
||||||
|
return (int)(*seed >> (48 - bits)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves the next random integer value. |
||||||
|
* The buffer used as seed must be read-write. |
||||||
|
* Usage: |
||||||
|
* <code> |
||||||
|
* __kernel void TestRandom(__global ulong* seeds) { |
||||||
|
* // ... |
||||||
|
* int i = randInt(seeds + get_global_id(0)); |
||||||
|
* // --- |
||||||
|
* } |
||||||
|
* </code> |
||||||
|
*/ |
||||||
|
inline int randInt(__global ulong* seed) { |
||||||
|
return randNext(32, seed); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves the next random integer value between 0 (inclusive) and n (exclusive). |
||||||
|
* The buffer used as seed must be read-write. |
||||||
|
* Usage: |
||||||
|
* <code> |
||||||
|
* __kernel void TestRandom(__global ulong* seeds) { |
||||||
|
* // ... |
||||||
|
* int i = randIntN(n, seeds + get_global_id(0)); |
||||||
|
* // --- |
||||||
|
* } |
||||||
|
* </code> |
||||||
|
*/ |
||||||
|
inline int randIntN(int n, __global ulong* seed) { |
||||||
|
if (n <= 0) |
||||||
|
return 0; |
||||||
|
|
||||||
|
if ((n & -n) == n) // i.e., n is a power of 2 |
||||||
|
return (int)((n * (long)randNext(31, seed)) >> 31); |
||||||
|
|
||||||
|
int bits, val; |
||||||
|
do { |
||||||
|
bits = randNext(31, seed); |
||||||
|
val = bits % n; |
||||||
|
} while (bits - val + (n-1) < 0); |
||||||
|
return val; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves the next random long value. |
||||||
|
* The buffer used as seed must be read-write. |
||||||
|
* Usage: |
||||||
|
* <code> |
||||||
|
* __kernel void TestRandom(__global ulong* seeds) { |
||||||
|
* // ... |
||||||
|
* long l = randLong(seeds + get_global_id(0)); |
||||||
|
* // --- |
||||||
|
* } |
||||||
|
* </code> |
||||||
|
*/ |
||||||
|
inline long randLong(__global ulong* seed) { |
||||||
|
// it's okay that the bottom word remains signed. |
||||||
|
return ((long)(randNext(32, seed)) << 32) + randNext(32, seed); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves the next random boolean value. |
||||||
|
* The buffer used as seed must be read-write. |
||||||
|
* Usage: |
||||||
|
* <code> |
||||||
|
* __kernel void TestRandom(__global ulong* seeds) { |
||||||
|
* // ... |
||||||
|
* bool b = randBool(seeds + get_global_id(0)); |
||||||
|
* // --- |
||||||
|
* } |
||||||
|
* </code> |
||||||
|
*/ |
||||||
|
inline bool randBool(__global ulong* seed) { |
||||||
|
return randNext(1, seed) != 0; |
||||||
|
} |
||||||
|
|
||||||
|
#ifdef RANDOM_DOUBLES |
||||||
|
/** |
||||||
|
* Retrieves the next random double value. |
||||||
|
* The buffer used as seed must be read-write. |
||||||
|
* To use this function, the preprocessor define RANDOM_DOUBLES must be set. |
||||||
|
* Usage: |
||||||
|
* <code> |
||||||
|
* __kernel void TestRandom(__global ulong* seeds) { |
||||||
|
* // ... |
||||||
|
* double d = randDouble(seeds + get_global_id(0)); |
||||||
|
* // --- |
||||||
|
* } |
||||||
|
* </code> |
||||||
|
*/ |
||||||
|
inline double randDouble(__global ulong* seed) { |
||||||
|
return (((long)(randNext(26, seed)) << 27) + randNext(27, seed)) |
||||||
|
/ (double)(1L << 53); |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves the next random float value. |
||||||
|
* The buffer used as seed must be read-write. |
||||||
|
* Usage: |
||||||
|
* <code> |
||||||
|
* __kernel void TestRandom(__global ulong* seeds) { |
||||||
|
* // ... |
||||||
|
* float f = randFloat(seeds + get_global_id(0)); |
||||||
|
* // --- |
||||||
|
* } |
||||||
|
* </code> |
||||||
|
*/ |
||||||
|
inline float randFloat(__global ulong* seed) |
||||||
|
{ |
||||||
|
return randNext(24, seed) / ((float)(1 << 24)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves the next random float values with a gaussian distribution of mean 0 |
||||||
|
* and derivation 1. |
||||||
|
* The buffer used as seed must be read-write. |
||||||
|
* Usage: |
||||||
|
* <code> |
||||||
|
* __kernel void TestRandom(__global ulong* seeds) { |
||||||
|
* // ... |
||||||
|
* float2 f2 = randGausianf(seeds + get_global_id(0)); |
||||||
|
* // --- |
||||||
|
* } |
||||||
|
* </code> |
||||||
|
*/ |
||||||
|
inline float2 randGaussianf(__global ulong* seed) { |
||||||
|
float v1, v2, s; |
||||||
|
do { |
||||||
|
v1 = 2 * randFloat(seed) - 1; // between -1 and 1 |
||||||
|
v2 = 2 * randFloat(seed) - 1; // between -1 and 1 |
||||||
|
s = v1 * v1 + v2 * v2; |
||||||
|
} while (s >= 1 || s == 0); |
||||||
|
float multiplier = sqrt(-2 * log(s)/s); |
||||||
|
return (float2) (v1 * multiplier, v2 * multiplier); |
||||||
|
} |
||||||
|
|
||||||
|
#ifdef RANDOM_DOUBLES |
||||||
|
/** |
||||||
|
* Retrieves the next random double values with a gaussian distribution of mean 0 |
||||||
|
* and derivation 1. |
||||||
|
* The buffer used as seed must be read-write. |
||||||
|
* To use this function, the preprocessor define RANDOM_DOUBLES must be set. |
||||||
|
* Usage: |
||||||
|
* <code> |
||||||
|
* __kernel void TestRandom(__global ulong* seeds) { |
||||||
|
* // ... |
||||||
|
* double2 f2 = randGausian(seeds + get_global_id(0)); |
||||||
|
* // --- |
||||||
|
* } |
||||||
|
* </code> |
||||||
|
*/ |
||||||
|
inline double2 randGaussian(__global ulong* seed) { |
||||||
|
double v1, v2, s; |
||||||
|
do { |
||||||
|
v1 = 2 * randDouble(seed) - 1; // between -1 and 1 |
||||||
|
v2 = 2 * randDouble(seed) - 1; // between -1 and 1 |
||||||
|
s = v1 * v1 + v2 * v2; |
||||||
|
} while (s >= 1 || s == 0); |
||||||
|
double multiplier = sqrt(-2 * log(s)/s); |
||||||
|
return (double2) (v1 * multiplier, v2 * multiplier); |
||||||
|
} |
||||||
|
#endif |
@ -0,0 +1,311 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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 jme3test.opencl; |
||||||
|
|
||||||
|
import com.jme3.app.SimpleApplication; |
||||||
|
import com.jme3.font.BitmapFont; |
||||||
|
import com.jme3.font.BitmapText; |
||||||
|
import com.jme3.math.ColorRGBA; |
||||||
|
import com.jme3.opencl.*; |
||||||
|
import com.jme3.system.AppSettings; |
||||||
|
import com.jme3.util.BufferUtils; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.nio.FloatBuffer; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Objects; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* Simple test checking if the basic functions of the OpenCL wrapper work |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class HelloOpenCL extends SimpleApplication { |
||||||
|
private static final Logger LOG = Logger.getLogger(HelloOpenCL.class.getName()); |
||||||
|
|
||||||
|
public static void main(String[] args){ |
||||||
|
HelloOpenCL app = new HelloOpenCL(); |
||||||
|
AppSettings settings = new AppSettings(true); |
||||||
|
settings.setOpenCLSupport(true); |
||||||
|
settings.setVSync(true); |
||||||
|
// settings.setRenderer(AppSettings.JOGL_OPENGL_FORWARD_COMPATIBLE);
|
||||||
|
app.setSettings(settings); |
||||||
|
app.start(); // start the game
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleInitApp() { |
||||||
|
BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt"); |
||||||
|
Context clContext = context.getOpenCLContext(); |
||||||
|
if (clContext == null) { |
||||||
|
BitmapText txt = new BitmapText(fnt); |
||||||
|
txt.setText("No OpenCL Context created!\nSee output log for details."); |
||||||
|
txt.setLocalTranslation(5, settings.getHeight() - 5, 0); |
||||||
|
guiNode.attachChild(txt); |
||||||
|
return; |
||||||
|
} |
||||||
|
CommandQueue clQueue = clContext.createQueue(); |
||||||
|
|
||||||
|
StringBuilder str = new StringBuilder(); |
||||||
|
str.append("OpenCL Context created:\n Platform: ") |
||||||
|
.append(clContext.getDevices().get(0).getPlatform().getName()) |
||||||
|
.append("\n Devices: ").append(clContext.getDevices()); |
||||||
|
str.append("\nTests:"); |
||||||
|
str.append("\n Buffers: ").append(testBuffer(clContext, clQueue)); |
||||||
|
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); |
||||||
|
guiNode.attachChild(txt1); |
||||||
|
|
||||||
|
flyCam.setEnabled(false); |
||||||
|
inputManager.setCursorVisible(true); |
||||||
|
} |
||||||
|
|
||||||
|
private static void assertEquals(byte expected, byte actual, String message) { |
||||||
|
if (expected != actual) { |
||||||
|
System.err.println(message+": expected="+expected+", actual="+actual); |
||||||
|
throw new AssertionError(); |
||||||
|
} |
||||||
|
} |
||||||
|
private static void assertEquals(long expected, long actual, String message) { |
||||||
|
if (expected != actual) { |
||||||
|
System.err.println(message+": expected="+expected+", actual="+actual); |
||||||
|
throw new AssertionError(); |
||||||
|
} |
||||||
|
} |
||||||
|
private static void assertEquals(double expected, double actual, String message) { |
||||||
|
if (Math.abs(expected - actual) >= 0.00001) { |
||||||
|
System.err.println(message+": expected="+expected+", actual="+actual); |
||||||
|
throw new AssertionError(); |
||||||
|
} |
||||||
|
} |
||||||
|
private static void assertEquals(Object expected, Object actual, String message) { |
||||||
|
if (!Objects.equals(expected, actual)) { |
||||||
|
System.err.println(message+": expected="+expected+", actual="+actual); |
||||||
|
throw new AssertionError(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean testBuffer(Context clContext, CommandQueue clQueue) { |
||||||
|
try { |
||||||
|
//create two buffers
|
||||||
|
ByteBuffer h1 = BufferUtils.createByteBuffer(256); |
||||||
|
Buffer b1 = clContext.createBuffer(256); |
||||||
|
ByteBuffer h2 = BufferUtils.createByteBuffer(256); |
||||||
|
Buffer b2 = clContext.createBuffer(256); |
||||||
|
|
||||||
|
//fill buffer
|
||||||
|
h2.rewind(); |
||||||
|
for (int i=0; i<256; ++i) { |
||||||
|
h2.put((byte)i); |
||||||
|
} |
||||||
|
h2.rewind(); |
||||||
|
b2.write(clQueue, h2); |
||||||
|
|
||||||
|
//copy b2 to b1
|
||||||
|
b2.copyTo(clQueue, b1); |
||||||
|
|
||||||
|
//read buffer
|
||||||
|
h1.rewind(); |
||||||
|
b1.read(clQueue, h1); |
||||||
|
h1.rewind(); |
||||||
|
for (int i=0; i<256; ++i) { |
||||||
|
byte b = h1.get(); |
||||||
|
assertEquals((byte) i, b, "Wrong byte read"); |
||||||
|
} |
||||||
|
|
||||||
|
//read buffer with offset
|
||||||
|
int low = 26; |
||||||
|
int high = 184; |
||||||
|
h1.position(5); |
||||||
|
Event event = b1.readAsync(clQueue, h1, high-low, low); |
||||||
|
event.waitForFinished(); |
||||||
|
h1.position(5); |
||||||
|
for (int i=0; i<high-low; ++i) { |
||||||
|
byte b = h1.get(); |
||||||
|
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; |
||||||
|
} catch (Exception ex) { |
||||||
|
LOG.log(Level.SEVERE, "Buffer test failed with:", ex); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean testKernel(Context clContext, CommandQueue clQueue) { |
||||||
|
try { |
||||||
|
//create fill code
|
||||||
|
String include = "#define TYPE float\n"; |
||||||
|
Program program = clContext.createProgramFromSourceFilesWithInclude(assetManager, include, "jme3test/opencl/Blas.cl"); |
||||||
|
program.build(); |
||||||
|
Kernel kernel = program.createKernel("Fill"); |
||||||
|
System.out.println("number of args: "+kernel.getArgCount()); |
||||||
|
|
||||||
|
//fill buffer
|
||||||
|
int size = 256+128; |
||||||
|
Buffer buffer = clContext.createBuffer(size*4); |
||||||
|
float value = 5; |
||||||
|
Event event = kernel.Run1(clQueue, new com.jme3.opencl.Kernel.WorkSize(buffer.getSize() / 4), buffer, value); |
||||||
|
event.waitForFinished(); |
||||||
|
|
||||||
|
//check if filled
|
||||||
|
ByteBuffer buf = buffer.map(clQueue, MappingAccess.MAP_READ_ONLY); |
||||||
|
FloatBuffer buff = buf.asFloatBuffer(); |
||||||
|
for (int i=0; i<size; ++i) { |
||||||
|
float v = buff.get(i); |
||||||
|
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"); |
||||||
|
return false; |
||||||
|
} catch (Exception ex) { |
||||||
|
LOG.log(Level.SEVERE, "kernel test failed with:", ex); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean testImages(Context clContext, CommandQueue clQueue) { |
||||||
|
try { |
||||||
|
//query supported formats
|
||||||
|
for (MemoryAccess ma : MemoryAccess.values()) { |
||||||
|
for (Image.ImageType type : Image.ImageType.values()) { |
||||||
|
try { |
||||||
|
System.out.println("Formats for " + ma + " and " + type + ": " + Arrays.toString(clContext.querySupportedFormats(ma, type))); |
||||||
|
} catch (UnsupportedOperationException e) { |
||||||
|
LOG.warning(e.getLocalizedMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//create an image
|
||||||
|
Image.ImageFormat format = new Image.ImageFormat(Image.ImageChannelOrder.RGBA, Image.ImageChannelType.FLOAT); |
||||||
|
Image.ImageDescriptor descr = new Image.ImageDescriptor(Image.ImageType.IMAGE_2D, 1920, 1080, 0, 0); |
||||||
|
Image image = clContext.createImage(MemoryAccess.READ_WRITE, format, descr); |
||||||
|
System.out.println("image created"); |
||||||
|
|
||||||
|
//check queries
|
||||||
|
assertEquals(descr.type, image.getImageType(), "Wrong image type"); |
||||||
|
assertEquals(format, image.getImageFormat(), "Wrong image format"); |
||||||
|
assertEquals(descr.width, image.getWidth(), "Wrong width"); |
||||||
|
assertEquals(descr.height, image.getHeight(), "Wrong height"); |
||||||
|
|
||||||
|
//fill with red and blue
|
||||||
|
ColorRGBA color1 = ColorRGBA.Red; |
||||||
|
ColorRGBA color2 = ColorRGBA.Blue; |
||||||
|
Event e1 = image.fillAsync(clQueue, new long[]{0,0,0}, new long[]{descr.width/2, descr.height, 1}, color1); |
||||||
|
Event e2 = image.fillAsync(clQueue, new long[]{descr.width/2,0,0}, new long[]{descr.width/2, descr.height, 1}, color2); |
||||||
|
e1.waitForFinished(); |
||||||
|
e2.waitForFinished(); |
||||||
|
|
||||||
|
//copy to a buffer
|
||||||
|
Buffer buffer = clContext.createBuffer(4*4*500*1024); |
||||||
|
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(); |
||||||
|
for (int x=0; x<500; ++x) { |
||||||
|
for (int y=0; y<1024; ++y) { |
||||||
|
float r = map1F.get(); |
||||||
|
float g = map1F.get(); |
||||||
|
float b = map1F.get(); |
||||||
|
float a = map1F.get(); |
||||||
|
assertEquals(1, r, "Wrong red component"); |
||||||
|
assertEquals(0, g, "Wrong green component"); |
||||||
|
assertEquals(0, b, "Wrong blue component"); |
||||||
|
assertEquals(1, a, "Wrong alpha component"); |
||||||
|
} |
||||||
|
} |
||||||
|
buffer.unmap(clQueue, map1); |
||||||
|
|
||||||
|
//create a second image
|
||||||
|
format = new Image.ImageFormat(Image.ImageChannelOrder.RGBA, Image.ImageChannelType.FLOAT); |
||||||
|
descr = new Image.ImageDescriptor(Image.ImageType.IMAGE_2D, 512, 512, 0, 0); |
||||||
|
Image image2 = clContext.createImage(MemoryAccess.READ_WRITE, format, descr); |
||||||
|
//copy an area of image1 to image2
|
||||||
|
image.copyTo(clQueue, image2, new long[]{1000, 20,0}, new long[]{0,0,0}, new long[]{512, 512,1}); |
||||||
|
//this area should be completely blue
|
||||||
|
Image.ImageMapping map2 = image2.map(clQueue, new long[]{0,0,0}, new long[]{512,512,1}, MappingAccess.MAP_READ_WRITE); |
||||||
|
FloatBuffer map2F = map2.buffer.asFloatBuffer(); |
||||||
|
for (int y=0; y<512; ++y) { |
||||||
|
for (int x=0; x<512; ++x) { |
||||||
|
long index = 4 * x + y * (map2.rowPitch / 4); |
||||||
|
map2F.position((int) index); |
||||||
|
float r = map2F.get(); |
||||||
|
float g = map2F.get(); |
||||||
|
float b = map2F.get(); |
||||||
|
float a = map2F.get(); |
||||||
|
assertEquals(0, r, "Wrong red component"); |
||||||
|
assertEquals(0, g, "Wrong green component"); |
||||||
|
assertEquals(1, b, "Wrong blue component"); |
||||||
|
assertEquals(1, a, "Wrong alpha component"); |
||||||
|
} |
||||||
|
} |
||||||
|
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; |
||||||
|
} catch (Exception ex) { |
||||||
|
LOG.log(Level.SEVERE, "image test failed with:", ex); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,255 @@ |
|||||||
|
/* |
||||||
|
* 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 jme3test.opencl; |
||||||
|
|
||||||
|
import com.jme3.app.SimpleApplication; |
||||||
|
import com.jme3.niftygui.NiftyJmeDisplay; |
||||||
|
import com.jme3.opencl.*; |
||||||
|
import com.jme3.system.AppSettings; |
||||||
|
import de.lessvoid.nifty.Nifty; |
||||||
|
import de.lessvoid.nifty.NiftyEventSubscriber; |
||||||
|
import de.lessvoid.nifty.controls.*; |
||||||
|
import de.lessvoid.nifty.screen.Screen; |
||||||
|
import de.lessvoid.nifty.screen.ScreenController; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.List; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author Sebastian Weiss |
||||||
|
*/ |
||||||
|
public class TestContextSwitching extends SimpleApplication implements ScreenController { |
||||||
|
private static final Logger LOG = Logger.getLogger(TestContextSwitching.class.getName()); |
||||||
|
|
||||||
|
private Nifty nifty; |
||||||
|
private Label infoLabel; |
||||||
|
private Button applyButton; |
||||||
|
private ListBox<String> platformListBox; |
||||||
|
private ListBox<String> deviceListBox; |
||||||
|
|
||||||
|
private static String selectedPlatform; |
||||||
|
private static String selectedDevice; |
||||||
|
private Context clContext; |
||||||
|
private static List<? extends Platform> availabePlatforms; |
||||||
|
private Buffer testBuffer; |
||||||
|
private boolean bufferCreated; |
||||||
|
|
||||||
|
/** |
||||||
|
* @param args the command line arguments |
||||||
|
*/ |
||||||
|
public static void main(String[] args) { |
||||||
|
new TestContextSwitching().start(); |
||||||
|
} |
||||||
|
|
||||||
|
public TestContextSwitching() { |
||||||
|
AppSettings settings = new AppSettings(true); |
||||||
|
settings.setOpenCLSupport(true); |
||||||
|
settings.setVSync(true); |
||||||
|
settings.setWidth(800); |
||||||
|
settings.setHeight(600); |
||||||
|
settings.setOpenCLPlatformChooser(CustomPlatformChooser.class); |
||||||
|
//settings.setRenderer(AppSettings.JOGL_OPENGL_FORWARD_COMPATIBLE);
|
||||||
|
|
||||||
|
setSettings(settings); |
||||||
|
setShowSettings(false); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleInitApp() { |
||||||
|
|
||||||
|
clContext = null; |
||||||
|
|
||||||
|
NiftyJmeDisplay niftyDisplay = NiftyJmeDisplay.newNiftyJmeDisplay( |
||||||
|
assetManager, |
||||||
|
inputManager, |
||||||
|
audioRenderer, |
||||||
|
guiViewPort); |
||||||
|
nifty = niftyDisplay.getNifty(); |
||||||
|
nifty.fromXml("jme3test/opencl/ContextSwitchingScreen.xml", "Screen", this); |
||||||
|
guiViewPort.addProcessor(niftyDisplay); |
||||||
|
inputManager.setCursorVisible(true); |
||||||
|
flyCam.setEnabled(false); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleUpdate(float tpf) { |
||||||
|
if (applyButton != null) { |
||||||
|
updateInfos(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
@SuppressWarnings("unchecked") |
||||||
|
public void bind(Nifty nifty, Screen screen) { |
||||||
|
applyButton = screen.findNiftyControl("ApplyButton", Button.class); |
||||||
|
platformListBox = screen.findNiftyControl("PlatformListBox", ListBox.class); |
||||||
|
deviceListBox = screen.findNiftyControl("DeviceListBox", ListBox.class); |
||||||
|
infoLabel = screen.findNiftyControl("InfoLabel", Label.class); |
||||||
|
|
||||||
|
updateInfos(); |
||||||
|
|
||||||
|
platformListBox.clear(); |
||||||
|
for (Platform p : availabePlatforms) { |
||||||
|
platformListBox.addItem(p.getName()); |
||||||
|
} |
||||||
|
platformListBox.selectItem(selectedPlatform); |
||||||
|
changePlatform(selectedPlatform); |
||||||
|
} |
||||||
|
|
||||||
|
private void updateInfos() { |
||||||
|
|
||||||
|
if (testBuffer == null && clContext != null && !bufferCreated) { |
||||||
|
try { |
||||||
|
testBuffer = clContext.createBuffer(1024); |
||||||
|
testBuffer.register(); |
||||||
|
LOG.info("Test buffer created"); |
||||||
|
} catch (OpenCLException ex) { |
||||||
|
LOG.log(Level.SEVERE, "Unable to create buffer", ex); |
||||||
|
} |
||||||
|
bufferCreated = true; |
||||||
|
} |
||||||
|
|
||||||
|
Context c = context.getOpenCLContext(); |
||||||
|
if (c == clContext) { |
||||||
|
return; |
||||||
|
} |
||||||
|
clContext = c; |
||||||
|
LOG.info("context changed"); |
||||||
|
testBuffer = null; |
||||||
|
bufferCreated = false; |
||||||
|
StringBuilder text = new StringBuilder(); |
||||||
|
text.append("Current context:\n"); |
||||||
|
text.append(" Platform: ").append(clContext.getDevices().get(0).getPlatform().getName()).append("\n"); |
||||||
|
text.append(" Device: ").append(clContext.getDevices().get(0).getName()).append("\n"); |
||||||
|
text.append(" Profile: ").append(clContext.getDevices().get(0).getProfile()).append("\n"); |
||||||
|
text.append(" Memory: ").append(clContext.getDevices().get(0).getGlobalMemorySize()).append(" B\n"); |
||||||
|
text.append(" Compute Units: ").append(clContext.getDevices().get(0).getComputeUnits()).append("\n"); |
||||||
|
infoLabel.setText(text.toString()); |
||||||
|
} |
||||||
|
|
||||||
|
@NiftyEventSubscriber(id="ApplyButton") |
||||||
|
public void onButton(String id, ButtonClickedEvent event) { |
||||||
|
LOG.log(Level.INFO, "Change context: platorm={0}, device={1}", new Object[]{selectedPlatform, selectedDevice}); |
||||||
|
restart(); |
||||||
|
} |
||||||
|
|
||||||
|
private void changePlatform(String platform) { |
||||||
|
selectedPlatform = platform; |
||||||
|
Platform p = null; |
||||||
|
for (Platform p2 : availabePlatforms) { |
||||||
|
if (p2.getName().equals(selectedPlatform)) { |
||||||
|
p = p2; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
deviceListBox.clear(); |
||||||
|
if (p == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
for (Device d : p.getDevices()) { |
||||||
|
deviceListBox.addItem(d.getName()); |
||||||
|
} |
||||||
|
deviceListBox.selectItem(selectedDevice); |
||||||
|
} |
||||||
|
|
||||||
|
@NiftyEventSubscriber(id="PlatformListBox") |
||||||
|
public void onPlatformChanged(String id, ListBoxSelectionChangedEvent<String> event) { |
||||||
|
String p = event.getSelection().isEmpty() ? null : event.getSelection().get(0); |
||||||
|
LOG.log(Level.INFO, "Selected platform changed to {0}", p); |
||||||
|
selectedPlatform = p; |
||||||
|
changePlatform(p); |
||||||
|
} |
||||||
|
|
||||||
|
@NiftyEventSubscriber(id="DeviceListBox") |
||||||
|
public void onDeviceChanged(String id, ListBoxSelectionChangedEvent<String> event) { |
||||||
|
String d = event.getSelection().isEmpty() ? null : event.getSelection().get(0); |
||||||
|
LOG.log(Level.INFO, "Selected device changed to {0}", d); |
||||||
|
selectedDevice = d; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onStartScreen() { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onEndScreen() { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public static class CustomPlatformChooser implements PlatformChooser { |
||||||
|
|
||||||
|
public CustomPlatformChooser() {} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<? extends Device> chooseDevices(List<? extends Platform> platforms) { |
||||||
|
availabePlatforms = platforms; |
||||||
|
|
||||||
|
Platform platform = null; |
||||||
|
for (Platform p : platforms) { |
||||||
|
if (p.getName().equals(selectedPlatform)) { |
||||||
|
platform = p; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
if (platform == null) { |
||||||
|
platform = platforms.get(0); |
||||||
|
} |
||||||
|
selectedPlatform = platform.getName(); |
||||||
|
|
||||||
|
Device device = null; |
||||||
|
for (Device d : platform.getDevices()) { |
||||||
|
if (d.getName().equals(selectedDevice)) { |
||||||
|
device = d; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
if (device == null) { |
||||||
|
for (Device d : platform.getDevices()) { |
||||||
|
if (d.getDeviceType() == Device.DeviceType.GPU) { |
||||||
|
device = d; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (device == null) { |
||||||
|
device = platform.getDevices().get(0); |
||||||
|
} |
||||||
|
selectedDevice = device.getName(); |
||||||
|
|
||||||
|
return Collections.singletonList(device); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,174 @@ |
|||||||
|
/* |
||||||
|
* 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 jme3test.opencl; |
||||||
|
|
||||||
|
import com.jme3.app.SimpleApplication; |
||||||
|
import com.jme3.font.BitmapFont; |
||||||
|
import com.jme3.font.BitmapText; |
||||||
|
import com.jme3.font.Rectangle; |
||||||
|
import com.jme3.opencl.*; |
||||||
|
import com.jme3.system.AppSettings; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.List; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class creates multiple instances of {@link TestVertexBufferSharing}. |
||||||
|
* This is used to test if multiple opencl instances can run in parallel. |
||||||
|
* @author Sebastian Weiss |
||||||
|
*/ |
||||||
|
public class TestMultipleApplications extends SimpleApplication { |
||||||
|
private static final Logger LOG = Logger.getLogger(TestMultipleApplications.class.getName()); |
||||||
|
|
||||||
|
private static final Object sync = new Object(); |
||||||
|
private static Platform selectedPlatform; |
||||||
|
private static List<? extends Device> availableDevices; |
||||||
|
private static int currentDeviceIndex; |
||||||
|
|
||||||
|
private Context clContext; |
||||||
|
private CommandQueue clQueue; |
||||||
|
private Kernel kernel; |
||||||
|
private Buffer buffer; |
||||||
|
private boolean failed; |
||||||
|
|
||||||
|
private BitmapText infoText; |
||||||
|
private BitmapText statusText; |
||||||
|
|
||||||
|
/** |
||||||
|
* @param args the command line arguments |
||||||
|
*/ |
||||||
|
public static void main(String[] args) { |
||||||
|
final AppSettings settings = new AppSettings(true); |
||||||
|
settings.setOpenCLSupport(true); |
||||||
|
settings.setVSync(true); |
||||||
|
settings.setOpenCLPlatformChooser(CustomPlatformChooser.class); |
||||||
|
settings.setRenderer(AppSettings.JOGL_OPENGL_FORWARD_COMPATIBLE); |
||||||
|
for (int i=0; i<2; ++i) { |
||||||
|
new Thread() { |
||||||
|
public void run() { |
||||||
|
if (currentDeviceIndex == -1) { |
||||||
|
return; |
||||||
|
} |
||||||
|
TestMultipleApplications app = new TestMultipleApplications(); |
||||||
|
app.setSettings(settings); |
||||||
|
app.setShowSettings(false); |
||||||
|
app.start(); |
||||||
|
} |
||||||
|
}.start(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static class CustomPlatformChooser implements PlatformChooser { |
||||||
|
|
||||||
|
public CustomPlatformChooser() {} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<? extends Device> chooseDevices(List<? extends Platform> platforms) { |
||||||
|
synchronized(sync) { |
||||||
|
if (currentDeviceIndex == -1) { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
|
||||||
|
Platform platform = platforms.get(0); |
||||||
|
availableDevices = platform.getDevices(); |
||||||
|
selectedPlatform = platform; |
||||||
|
|
||||||
|
Device device = platform.getDevices().get(currentDeviceIndex); |
||||||
|
currentDeviceIndex ++; |
||||||
|
if (currentDeviceIndex >= availableDevices.size()) { |
||||||
|
currentDeviceIndex = -1; |
||||||
|
} |
||||||
|
|
||||||
|
return Collections.singletonList(device); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleInitApp() { |
||||||
|
clContext = context.getOpenCLContext(); |
||||||
|
if (clContext == null) { |
||||||
|
LOG.severe("No OpenCL context found"); |
||||||
|
stop(); |
||||||
|
return; |
||||||
|
} |
||||||
|
Device device = clContext.getDevices().get(0); |
||||||
|
clQueue = clContext.createQueue(device); |
||||||
|
clQueue.register(); |
||||||
|
|
||||||
|
String source = "" |
||||||
|
+ "__kernel void Fill(__global float* vb, float v)\n" |
||||||
|
+ "{\n" |
||||||
|
+ " int idx = get_global_id(0);\n" |
||||||
|
+ " vb[idx] = v;\n" |
||||||
|
+ "}\n"; |
||||||
|
Program program = clContext.createProgramFromSourceCode(source); |
||||||
|
program.build(); |
||||||
|
program.register(); |
||||||
|
kernel = program.createKernel("Fill"); |
||||||
|
kernel.register(); |
||||||
|
|
||||||
|
buffer = clContext.createBuffer(4); |
||||||
|
buffer.register(); |
||||||
|
|
||||||
|
flyCam.setEnabled(false); |
||||||
|
inputManager.setCursorVisible(true); |
||||||
|
|
||||||
|
BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt"); |
||||||
|
infoText = new BitmapText(fnt, false); |
||||||
|
//infoText.setBox(new Rectangle(0, 0, settings.getWidth(), settings.getHeight()));
|
||||||
|
infoText.setText("Device: "+clContext.getDevices()); |
||||||
|
infoText.setLocalTranslation(0, settings.getHeight(), 0); |
||||||
|
guiNode.attachChild(infoText); |
||||||
|
statusText = new BitmapText(fnt, false); |
||||||
|
//statusText.setBox(new Rectangle(0, 0, settings.getWidth(), settings.getHeight()));
|
||||||
|
statusText.setText("Running"); |
||||||
|
statusText.setLocalTranslation(0, settings.getHeight() - infoText.getHeight() - 2, 0); |
||||||
|
guiNode.attachChild(statusText); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleUpdate(float tpf) { |
||||||
|
//call kernel to test if it is still working
|
||||||
|
if (!failed) { |
||||||
|
try { |
||||||
|
kernel.Run1NoEvent(clQueue, new Kernel.WorkSize(1), buffer, 1.0f); |
||||||
|
} catch (OpenCLException ex) { |
||||||
|
LOG.log(Level.SEVERE, "Kernel call not working anymore", ex); |
||||||
|
failed = true; |
||||||
|
statusText.setText("Failed"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,403 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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 jme3test.opencl; |
||||||
|
|
||||||
|
import com.jme3.app.SimpleApplication; |
||||||
|
import com.jme3.font.BitmapFont; |
||||||
|
import com.jme3.font.BitmapText; |
||||||
|
import com.jme3.math.ColorRGBA; |
||||||
|
import com.jme3.math.FastMath; |
||||||
|
import com.jme3.math.Matrix3f; |
||||||
|
import com.jme3.math.Matrix4f; |
||||||
|
import com.jme3.opencl.*; |
||||||
|
import com.jme3.system.AppSettings; |
||||||
|
import com.jme3.util.BufferUtils; |
||||||
|
import java.nio.*; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Objects; |
||||||
|
import java.util.Random; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* Test class for the build in libraries |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class TestOpenCLLibraries extends SimpleApplication { |
||||||
|
private static final Logger LOG = Logger.getLogger(TestOpenCLLibraries.class.getName()); |
||||||
|
|
||||||
|
public static void main(String[] args){ |
||||||
|
TestOpenCLLibraries app = new TestOpenCLLibraries(); |
||||||
|
AppSettings settings = new AppSettings(true); |
||||||
|
settings.setOpenCLSupport(true); |
||||||
|
settings.setVSync(true); |
||||||
|
// settings.setRenderer(AppSettings.JOGL_OPENGL_FORWARD_COMPATIBLE);
|
||||||
|
app.setSettings(settings); |
||||||
|
app.start(); // start the game
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleInitApp() { |
||||||
|
BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt"); |
||||||
|
Context clContext = context.getOpenCLContext(); |
||||||
|
if (clContext == null) { |
||||||
|
BitmapText txt = new BitmapText(fnt); |
||||||
|
txt.setText("No OpenCL Context created!\nSee output log for details."); |
||||||
|
txt.setLocalTranslation(5, settings.getHeight() - 5, 0); |
||||||
|
guiNode.attachChild(txt); |
||||||
|
return; |
||||||
|
} |
||||||
|
CommandQueue clQueue = clContext.createQueue(clContext.getDevices().get(0)); |
||||||
|
|
||||||
|
StringBuilder str = new StringBuilder(); |
||||||
|
str.append("OpenCL Context created:\n Platform: ") |
||||||
|
.append(clContext.getDevices().get(0).getPlatform().getName()) |
||||||
|
.append("\n Devices: ").append(clContext.getDevices()); |
||||||
|
str.append("\nTests:"); |
||||||
|
str.append("\n Random numbers: ").append(testRandom(clContext, clQueue)); |
||||||
|
str.append("\n Matrix3f: ").append(testMatrix3f(clContext, clQueue)); |
||||||
|
str.append("\n Matrix4f: ").append(testMatrix4f(clContext, clQueue)); |
||||||
|
|
||||||
|
clQueue.release(); |
||||||
|
|
||||||
|
BitmapText txt1 = new BitmapText(fnt); |
||||||
|
txt1.setText(str.toString()); |
||||||
|
txt1.setLocalTranslation(5, settings.getHeight() - 5, 0); |
||||||
|
guiNode.attachChild(txt1); |
||||||
|
|
||||||
|
flyCam.setEnabled(false); |
||||||
|
inputManager.setCursorVisible(true); |
||||||
|
} |
||||||
|
|
||||||
|
private static void assertEquals(byte expected, byte actual, String message) { |
||||||
|
if (expected != actual) { |
||||||
|
System.err.println(message+": expected="+expected+", actual="+actual); |
||||||
|
throw new AssertionError(); |
||||||
|
} |
||||||
|
} |
||||||
|
private static void assertEquals(long expected, long actual, String message) { |
||||||
|
if (expected != actual) { |
||||||
|
System.err.println(message+": expected="+expected+", actual="+actual); |
||||||
|
throw new AssertionError(); |
||||||
|
} |
||||||
|
} |
||||||
|
private static void assertEquals(double expected, double actual, String message) { |
||||||
|
if (Math.abs(expected - actual) >= 0.00001) { |
||||||
|
System.err.println(message+": expected="+expected+", actual="+actual); |
||||||
|
throw new AssertionError(); |
||||||
|
} |
||||||
|
} |
||||||
|
private static void assertEquals(Object expected, Object actual, String message) { |
||||||
|
if (!Objects.equals(expected, actual)) { |
||||||
|
System.err.println(message+": expected="+expected+", actual="+actual); |
||||||
|
throw new AssertionError(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean testRandom(Context clContext, CommandQueue clQueue) { |
||||||
|
try { |
||||||
|
//test for doubles
|
||||||
|
boolean supportsDoubles = clContext.getDevices().get(0).hasDouble(); |
||||||
|
|
||||||
|
//create code
|
||||||
|
String code = "" |
||||||
|
+ "#import \"Common/OpenCL/Random.clh\"\n" |
||||||
|
+ "__kernel void TestBool(__global ulong* seeds, __global uchar* results) {\n" |
||||||
|
+ " results[get_global_id(0)] = randBool(seeds + get_global_id(0)) ? 1 : 0;\n" |
||||||
|
+ "}\n" |
||||||
|
+ "__kernel void TestInt(__global ulong* seeds, __global int* results) {\n" |
||||||
|
+ " results[get_global_id(0)] = randInt(seeds + get_global_id(0));\n" |
||||||
|
+ "}\n" |
||||||
|
+ "__kernel void TestIntN(__global ulong* seeds, int n, __global int* results) {\n" |
||||||
|
+ " results[get_global_id(0)] = randIntN(n, seeds + get_global_id(0));\n" |
||||||
|
+ "}\n" |
||||||
|
+ "__kernel void TestLong(__global ulong* seeds, __global long* results) {\n" |
||||||
|
+ " results[get_global_id(0)] = randLong(seeds + get_global_id(0));\n" |
||||||
|
+ "}\n" |
||||||
|
+ "__kernel void TestFloat(__global ulong* seeds, __global float* results) {\n" |
||||||
|
+ " results[get_global_id(0)] = randFloat(seeds + get_global_id(0));\n" |
||||||
|
+ "}\n" |
||||||
|
+ "#ifdef RANDOM_DOUBLES\n" |
||||||
|
+ "__kernel void TestDouble(__global ulong* seeds, __global double* results) {\n" |
||||||
|
+ " results[get_global_id(0)] = randDouble(seeds + get_global_id(0));\n" |
||||||
|
+ "}\n" |
||||||
|
+ "#endif\n"; |
||||||
|
if (supportsDoubles) { |
||||||
|
code = "#define RANDOM_DOUBLES\n" + code; |
||||||
|
} |
||||||
|
Program program = clContext.createProgramFromSourceCodeWithDependencies(code, assetManager); |
||||||
|
program.build(); |
||||||
|
|
||||||
|
int count = 256; |
||||||
|
Kernel.WorkSize ws = new Kernel.WorkSize(count); |
||||||
|
|
||||||
|
//create seeds
|
||||||
|
Random initRandom = new Random(); |
||||||
|
long[] seeds = new long[count]; |
||||||
|
Random[] randoms = new Random[count]; |
||||||
|
for (int i=0; i<count; ++i) { |
||||||
|
seeds[i] = initRandom.nextLong(); |
||||||
|
randoms[i] = new Random(seeds[i]); |
||||||
|
seeds[i] = (seeds[i] ^ 0x5DEECE66DL) & ((1L << 48) - 1); //needed because the Random constructor scrambles the initial seed
|
||||||
|
} |
||||||
|
com.jme3.opencl.Buffer seedsBuffer = clContext.createBuffer(8 * count); |
||||||
|
ByteBuffer tmpByteBuffer = BufferUtils.createByteBuffer(8 * count); |
||||||
|
tmpByteBuffer.asLongBuffer().put(seeds); |
||||||
|
seedsBuffer.write(clQueue, tmpByteBuffer); |
||||||
|
|
||||||
|
//test it
|
||||||
|
ByteBuffer resultByteBuffer = BufferUtils.createByteBuffer(8 * count); |
||||||
|
IntBuffer resultIntBuffer = resultByteBuffer.asIntBuffer(); |
||||||
|
LongBuffer resultLongBuffer = resultByteBuffer.asLongBuffer(); |
||||||
|
FloatBuffer resultFloatBuffer = resultByteBuffer.asFloatBuffer(); |
||||||
|
DoubleBuffer resultDoubleBuffer = resultByteBuffer.asDoubleBuffer(); |
||||||
|
com.jme3.opencl.Buffer resultBuffer = clContext.createBuffer(8 * count); |
||||||
|
//boolean
|
||||||
|
Kernel testBoolKernel = program.createKernel("TestBool"); |
||||||
|
testBoolKernel.Run1NoEvent(clQueue, ws, seedsBuffer, resultBuffer); |
||||||
|
resultByteBuffer.rewind(); |
||||||
|
resultBuffer.read(clQueue, resultByteBuffer); |
||||||
|
for (int i=0; i<count; ++i) { |
||||||
|
assertEquals(randoms[i].nextBoolean() ? 1 : 0, resultByteBuffer.get(i), "randBool at i="+i); |
||||||
|
} |
||||||
|
testBoolKernel.release(); |
||||||
|
//int
|
||||||
|
Kernel testIntKernel = program.createKernel("TestInt"); |
||||||
|
testIntKernel.Run1NoEvent(clQueue, ws, seedsBuffer, resultBuffer); |
||||||
|
resultByteBuffer.rewind(); |
||||||
|
resultBuffer.read(clQueue, resultByteBuffer); |
||||||
|
for (int i=0; i<count; ++i) { |
||||||
|
assertEquals(randoms[i].nextInt(), resultIntBuffer.get(i), "randInt at i="+i); |
||||||
|
} |
||||||
|
testIntKernel.release(); |
||||||
|
//int n
|
||||||
|
Kernel testIntNKernel = program.createKernel("TestIntN"); |
||||||
|
testIntNKernel.Run1NoEvent(clQueue, ws, seedsBuffer, 186, resultBuffer); |
||||||
|
resultByteBuffer.rewind(); |
||||||
|
resultBuffer.read(clQueue, resultByteBuffer); |
||||||
|
for (int i=0; i<count; ++i) { |
||||||
|
assertEquals(randoms[i].nextInt(186), resultIntBuffer.get(i), "randInt at i="+i+" with n="+186); |
||||||
|
} |
||||||
|
testIntNKernel.Run1NoEvent(clQueue, ws, seedsBuffer, 97357, resultBuffer); |
||||||
|
resultByteBuffer.rewind(); |
||||||
|
resultBuffer.read(clQueue, resultByteBuffer); |
||||||
|
for (int i=0; i<count; ++i) { |
||||||
|
assertEquals(randoms[i].nextInt(97357), resultIntBuffer.get(i), "randInt at i="+i+" with n="+97357); |
||||||
|
} |
||||||
|
testIntNKernel.release(); |
||||||
|
//long
|
||||||
|
Kernel testLongKernel = program.createKernel("TestLong"); |
||||||
|
testLongKernel.Run1NoEvent(clQueue, ws, seedsBuffer, resultBuffer); |
||||||
|
resultByteBuffer.rewind(); |
||||||
|
resultBuffer.read(clQueue, resultByteBuffer); |
||||||
|
for (int i=0; i<count; ++i) { |
||||||
|
assertEquals(randoms[i].nextLong(), resultLongBuffer.get(i), "randLong at i="+i); |
||||||
|
} |
||||||
|
testLongKernel.release(); |
||||||
|
//float
|
||||||
|
Kernel testFloatKernel = program.createKernel("TestFloat"); |
||||||
|
testFloatKernel.Run1NoEvent(clQueue, ws, seedsBuffer, resultBuffer); |
||||||
|
resultByteBuffer.rewind(); |
||||||
|
resultBuffer.read(clQueue, resultByteBuffer); |
||||||
|
for (int i=0; i<count; ++i) { |
||||||
|
assertEquals(randoms[i].nextFloat(), resultFloatBuffer.get(i), "randFloat at i="+i); |
||||||
|
} |
||||||
|
testFloatKernel.release(); |
||||||
|
//double
|
||||||
|
if (supportsDoubles) { |
||||||
|
Kernel testDoubleKernel = program.createKernel("TestDouble"); |
||||||
|
testDoubleKernel.Run1NoEvent(clQueue, ws, seedsBuffer, resultBuffer); |
||||||
|
resultByteBuffer.rewind(); |
||||||
|
resultBuffer.read(clQueue, resultByteBuffer); |
||||||
|
for (int i=0; i<count; ++i) { |
||||||
|
assertEquals(randoms[i].nextDouble(), resultDoubleBuffer.get(i), "randLong at i="+i); |
||||||
|
} |
||||||
|
testDoubleKernel.release(); |
||||||
|
} |
||||||
|
|
||||||
|
seedsBuffer.release(); |
||||||
|
resultBuffer.release(); |
||||||
|
program.release(); |
||||||
|
|
||||||
|
} catch (AssertionError ex) { |
||||||
|
LOG.log(Level.SEVERE, "random test failed with an assertion error"); |
||||||
|
return false; |
||||||
|
} catch (Exception ex) { |
||||||
|
LOG.log(Level.SEVERE, "random test failed with:", ex); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean testMatrix3f(Context clContext, CommandQueue clQueue) { |
||||||
|
try { |
||||||
|
|
||||||
|
String code = "" |
||||||
|
+ "#import \"Common/OpenCL/Matrix3f.clh\"\n" |
||||||
|
+ "\n" |
||||||
|
+ "__kernel void TestMatrix3f_1(__global char* result)\n" |
||||||
|
+ "{\n" |
||||||
|
+ " mat3 id = mat3Identity();\n" |
||||||
|
+ " mat3 m1 = mat3FromRows( (float3)(23,-3,10.4f), (float3)(5,-8,2.22f), (float3)(-1,0,34) );\n" |
||||||
|
+ " mat3 m1Inv = mat3Invert(m1);\n" |
||||||
|
+ " mat3 m1Res = mat3Mult(m1, m1Inv);\n" |
||||||
|
+ " result[0] = mat3Equals(id, m1Res, 0.0001f) ? 1 : 0;\n" |
||||||
|
+ "}\n" |
||||||
|
+ "\n" |
||||||
|
+ "__kernel void TestMatrix3f_2(mat3 m1, float a, mat3 m2, mat3 mRes, __global char* result)\n" |
||||||
|
+ "{\n" |
||||||
|
+ " mat3 m = mat3Transpose(m1);\n" |
||||||
|
+ " m = mat3Add(mat3Scale(m, a), m2);\n" |
||||||
|
+ " result[0] = mat3Equals(mRes, m, 0.01f) ? 1 : 0;\n" |
||||||
|
+ "}\n"; |
||||||
|
Program program = clContext.createProgramFromSourceCodeWithDependencies(code, assetManager); |
||||||
|
program.build(); |
||||||
|
com.jme3.opencl.Buffer buffer = clContext.createBuffer(1); |
||||||
|
|
||||||
|
Kernel testMatrix3fKernel1 = program.createKernel("TestMatrix3f_1"); |
||||||
|
testMatrix3fKernel1.Run1NoEvent(clQueue, new Kernel.WorkSize(1), buffer); |
||||||
|
ByteBuffer bb = buffer.map(clQueue, MappingAccess.MAP_READ_ONLY); |
||||||
|
if (bb.get() == 0) { |
||||||
|
LOG.severe("Matrix inversion failed"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
buffer.unmap(clQueue, bb); |
||||||
|
testMatrix3fKernel1.release(); |
||||||
|
|
||||||
|
Kernel testMatrix3fKernel2 = program.createKernel("TestMatrix3f_2"); |
||||||
|
Matrix3f m1 = new Matrix3f(13.24f, -0.234f, 42, 83.23f, -34.2f, 3.2f, 0.25f, -42, 7.64f); |
||||||
|
Matrix3f m2 = new Matrix3f(-5.2f, 0.757f, 2.01f, 12.0f, -6, 2, 0.01f, 9, 2.255f); |
||||||
|
Matrix3f mRes = new Matrix3f(-31.68f, -165.703f, 1.51f, 12.468f, 62.4f, 86, -83.99f, 2.6f, -13.025f); |
||||||
|
testMatrix3fKernel2.Run1NoEvent(clQueue, new Kernel.WorkSize(1), m1, -2.0f, m2, mRes, buffer); |
||||||
|
bb = buffer.map(clQueue, MappingAccess.MAP_READ_ONLY); |
||||||
|
if (bb.get() == 0) { |
||||||
|
LOG.severe("Matrix add, multiply, transpose failed"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
buffer.unmap(clQueue, bb); |
||||||
|
testMatrix3fKernel2.release(); |
||||||
|
|
||||||
|
buffer.release(); |
||||||
|
|
||||||
|
} catch (AssertionError ex) { |
||||||
|
LOG.log(Level.SEVERE, "matrix3f test failed with an assertion error"); |
||||||
|
return false; |
||||||
|
} catch (Exception ex) { |
||||||
|
LOG.log(Level.SEVERE, "matrix3f test failed with:", ex); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean testMatrix4f(Context clContext, CommandQueue clQueue) { |
||||||
|
try { |
||||||
|
|
||||||
|
String code = "" |
||||||
|
+ "#import \"Common/OpenCL/Matrix4f.clh\"\n" |
||||||
|
+ "\n" |
||||||
|
+ "__kernel void TestMatrix4f_1(mat4 m1, __global char* result)\n" |
||||||
|
+ "{\n" |
||||||
|
+ " mat4 id = mat4Identity();\n" |
||||||
|
+ " mat4 m1Inv = mat4Invert(m1);\n" |
||||||
|
+ " mat4 m1Res = mat4Mult(m1, m1Inv);\n" |
||||||
|
+ " result[0] = mat4Equals(id, m1Res, 0.0001f) ? 1 : 0;\n" |
||||||
|
+ "}\n" |
||||||
|
+ "\n" |
||||||
|
+ "__kernel void TestMatrix4f_2(mat4 m1, float d, mat4 m2, mat4 m3, __global char* result)\n" |
||||||
|
+ "{\n" |
||||||
|
+ " float d2 = mat4Determinant(m1);\n" |
||||||
|
+ " result[0] = fabs(d - d2) < 0.0001f ? 1 : 0;\n" |
||||||
|
+ " mat4 res = mat4Transpose(m1);\n" |
||||||
|
+ " result[1] = mat4Equals(res, m2, 0.0001f) ? 1 : 0;\n" |
||||||
|
+ " res = mat4Adjoint(m1);\n" |
||||||
|
+ " result[2] = mat4Equals(res, m3, 0.0001f) ? 1 : 0;\n" |
||||||
|
+ "}\n"; |
||||||
|
Program program = clContext.createProgramFromSourceCodeWithDependencies(code, assetManager); |
||||||
|
program.build(); |
||||||
|
com.jme3.opencl.Buffer buffer = clContext.createBuffer(3); |
||||||
|
|
||||||
|
Random rand = new Random(1561); |
||||||
|
|
||||||
|
Kernel testMatrix4fKernel1 = program.createKernel("TestMatrix4f_1"); |
||||||
|
Matrix4f m1 = new Matrix4f(); |
||||||
|
do { |
||||||
|
for (int i=0; i<4; ++i) { |
||||||
|
for (int j=0; j<4; ++j) { |
||||||
|
m1.set(i, j, rand.nextFloat()*20 - 10); |
||||||
|
} |
||||||
|
} |
||||||
|
} while (FastMath.abs(m1.determinant()) < 0.00001f); |
||||||
|
testMatrix4fKernel1.Run1NoEvent(clQueue, new Kernel.WorkSize(1), m1, buffer); |
||||||
|
ByteBuffer bb = buffer.map(clQueue, MappingAccess.MAP_READ_ONLY); |
||||||
|
if (bb.get() == 0) { |
||||||
|
LOG.severe("Matrix inversion failed"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
buffer.unmap(clQueue, bb); |
||||||
|
testMatrix4fKernel1.release(); |
||||||
|
|
||||||
|
Kernel testMatrix4fKernel2 = program.createKernel("TestMatrix4f_2"); |
||||||
|
for (int i=0; i<4; ++i) { |
||||||
|
for (int j=0; j<4; ++j) { |
||||||
|
m1.set(i, j, rand.nextFloat()*20 - 10); |
||||||
|
} |
||||||
|
} |
||||||
|
testMatrix4fKernel2.Run1NoEvent(clQueue, new Kernel.WorkSize(1), m1, m1.determinant(), m1.transpose(), m1.adjoint(), buffer); |
||||||
|
bb = buffer.map(clQueue, MappingAccess.MAP_READ_ONLY); |
||||||
|
if (bb.get() == 0) { |
||||||
|
LOG.severe("Matrix determinant computation failed"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (bb.get() == 0) { |
||||||
|
LOG.severe("Matrix transposing failed"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (bb.get() == 0) { |
||||||
|
LOG.severe("Matrix adjoint computation failed"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
buffer.unmap(clQueue, bb); |
||||||
|
testMatrix4fKernel2.release(); |
||||||
|
|
||||||
|
buffer.release(); |
||||||
|
|
||||||
|
} catch (AssertionError ex) { |
||||||
|
LOG.log(Level.SEVERE, "matrix4f test failed with an assertion error"); |
||||||
|
return false; |
||||||
|
} catch (Exception ex) { |
||||||
|
LOG.log(Level.SEVERE, "matrix4f test failed with:", ex); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,186 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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 jme3test.opencl; |
||||||
|
|
||||||
|
import com.jme3.app.SimpleApplication; |
||||||
|
import com.jme3.material.Material; |
||||||
|
import com.jme3.math.ColorRGBA; |
||||||
|
import com.jme3.opencl.*; |
||||||
|
import com.jme3.scene.Geometry; |
||||||
|
import com.jme3.scene.VertexBuffer; |
||||||
|
import com.jme3.scene.shape.Box; |
||||||
|
import com.jme3.system.AppSettings; |
||||||
|
import com.jme3.system.JmeSystem; |
||||||
|
import com.jme3.util.BufferUtils; |
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.nio.file.Files; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* This test class tests the capability to read and modify an OpenGL vertex buffer. |
||||||
|
* It is also shown how to use the program binaries to implement a simple program |
||||||
|
* cache. |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class TestVertexBufferSharing extends SimpleApplication { |
||||||
|
private static final Logger LOG = Logger.getLogger(TestVertexBufferSharing.class.getName()); |
||||||
|
|
||||||
|
private int initCounter; |
||||||
|
private Context clContext; |
||||||
|
private CommandQueue clQueue; |
||||||
|
private Geometry geom; |
||||||
|
private Buffer buffer; |
||||||
|
private Kernel kernel; |
||||||
|
private com.jme3.opencl.Kernel.WorkSize ws; |
||||||
|
private float time; |
||||||
|
|
||||||
|
public static void main(String[] args){ |
||||||
|
TestVertexBufferSharing app = new TestVertexBufferSharing(); |
||||||
|
AppSettings settings = new AppSettings(true); |
||||||
|
settings.setOpenCLSupport(true); |
||||||
|
settings.setVSync(false); |
||||||
|
// settings.setRenderer(AppSettings.JOGL_OPENGL_FORWARD_COMPATIBLE);
|
||||||
|
app.setSettings(settings); |
||||||
|
app.start(); // start the game
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleInitApp() { |
||||||
|
initOpenCL1(); |
||||||
|
|
||||||
|
Box b = new Box(1, 1, 1); // create cube shape
|
||||||
|
geom = new Geometry("Box", b); // create cube geometry from the shape
|
||||||
|
Material mat = new Material(assetManager, |
||||||
|
"Common/MatDefs/Misc/Unshaded.j3md"); // create a simple material
|
||||||
|
mat.setColor("Color", ColorRGBA.Blue); // set color of material to blue
|
||||||
|
geom.setMaterial(mat); // set the cube's material
|
||||||
|
rootNode.attachChild(geom); // make the cube appear in the scene
|
||||||
|
|
||||||
|
initCounter = 0; |
||||||
|
time = 0; |
||||||
|
|
||||||
|
flyCam.setDragToRotate(true); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleUpdate(float tpf) { |
||||||
|
super.simpleUpdate(tpf); |
||||||
|
|
||||||
|
if (initCounter < 2) { |
||||||
|
initCounter++; |
||||||
|
} else if (initCounter == 2) { |
||||||
|
//when initCounter reaches 2, the scene was drawn once and the texture was uploaded to the GPU
|
||||||
|
//then we can bind the texture to OpenCL
|
||||||
|
initOpenCL2(); |
||||||
|
updateOpenCL(tpf); |
||||||
|
initCounter = 3; |
||||||
|
} else { |
||||||
|
updateOpenCL(tpf); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void initOpenCL1() { |
||||||
|
clContext = context.getOpenCLContext(); |
||||||
|
Device device = clContext.getDevices().get(0); |
||||||
|
clQueue = clContext.createQueue(device); |
||||||
|
clQueue.register(); |
||||||
|
//create kernel
|
||||||
|
Program program = null; |
||||||
|
File tmpFolder = JmeSystem.getStorageFolder(); |
||||||
|
File binaryFile = new File(tmpFolder, getClass().getSimpleName()+".clc"); |
||||||
|
try { |
||||||
|
//attempt to load cached binary
|
||||||
|
byte[] bytes = Files.readAllBytes(binaryFile.toPath()); |
||||||
|
ByteBuffer bb = BufferUtils.createByteBuffer(bytes); |
||||||
|
program = clContext.createProgramFromBinary(bb, device); |
||||||
|
program.build(); |
||||||
|
LOG.info("reuse program from cached binaries"); |
||||||
|
} catch (java.nio.file.NoSuchFileException ex) { |
||||||
|
//do nothing, cache was not created yet
|
||||||
|
} catch (Exception ex) { |
||||||
|
LOG.log(Level.INFO, "Unable to use cached program binaries", ex); |
||||||
|
} |
||||||
|
if (program == null) { |
||||||
|
//build from sources
|
||||||
|
String source = "" |
||||||
|
+ "__kernel void ScaleKernel(__global float* vb, float scale)\n" |
||||||
|
+ "{\n" |
||||||
|
+ " int idx = get_global_id(0);\n" |
||||||
|
+ " float3 pos = vload3(idx, vb);\n" |
||||||
|
+ " pos *= scale;\n" |
||||||
|
+ " vstore3(pos, idx, vb);\n" |
||||||
|
+ "}\n"; |
||||||
|
program = clContext.createProgramFromSourceCode(source); |
||||||
|
program.build(); |
||||||
|
//Save binary
|
||||||
|
try { |
||||||
|
ByteBuffer bb = program.getBinary(device); |
||||||
|
byte[] bytes = new byte[bb.remaining()]; |
||||||
|
bb.get(bytes); |
||||||
|
Files.write(binaryFile.toPath(), bytes); |
||||||
|
} catch (UnsupportedOperationException | OpenCLException | IOException ex) { |
||||||
|
LOG.log(Level.SEVERE, "Unable to save program binaries", ex); |
||||||
|
} |
||||||
|
LOG.info("create new program from sources"); |
||||||
|
} |
||||||
|
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) { |
||||||
|
//advect time
|
||||||
|
time += tpf; |
||||||
|
|
||||||
|
//aquire resource
|
||||||
|
buffer.acquireBufferForSharingNoEvent(clQueue); |
||||||
|
//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.Run1NoEvent(clQueue, ws, buffer, scale); |
||||||
|
|
||||||
|
//release resource
|
||||||
|
buffer.releaseBufferForSharingNoEvent(clQueue); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,183 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 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 jme3test.opencl; |
||||||
|
|
||||||
|
import com.jme3.app.SimpleApplication; |
||||||
|
import com.jme3.input.MouseInput; |
||||||
|
import com.jme3.input.controls.ActionListener; |
||||||
|
import com.jme3.input.controls.AnalogListener; |
||||||
|
import com.jme3.input.controls.MouseAxisTrigger; |
||||||
|
import com.jme3.input.controls.MouseButtonTrigger; |
||||||
|
import com.jme3.math.Vector2f; |
||||||
|
import com.jme3.opencl.*; |
||||||
|
import com.jme3.system.AppSettings; |
||||||
|
import com.jme3.texture.Texture2D; |
||||||
|
import com.jme3.ui.Picture; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* This test class tests the capability to write to a GL texture from OpenCL. |
||||||
|
* Move the mouse around while pressing the left mouse key to modify the fractal. |
||||||
|
* |
||||||
|
* In addition, this test shows how to use {@link ProgramCache}. |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class TestWriteToTexture extends SimpleApplication implements AnalogListener, ActionListener { |
||||||
|
private static final Logger LOG = Logger.getLogger(TestWriteToTexture.class.getName()); |
||||||
|
private static final float MOUSE_SPEED = 0.5f; |
||||||
|
|
||||||
|
private Texture2D tex; |
||||||
|
private int initCounter; |
||||||
|
private Context clContext; |
||||||
|
private CommandQueue clQueue; |
||||||
|
private ProgramCache programCache; |
||||||
|
private Kernel kernel; |
||||||
|
private Vector2f C; |
||||||
|
private Image texCL; |
||||||
|
private boolean dragging; |
||||||
|
|
||||||
|
public static void main(String[] args){ |
||||||
|
TestWriteToTexture app = new TestWriteToTexture(); |
||||||
|
AppSettings settings = new AppSettings(true); |
||||||
|
settings.setOpenCLSupport(true); |
||||||
|
settings.setVSync(false); |
||||||
|
// settings.setRenderer(AppSettings.JOGL_OPENGL_FORWARD_COMPATIBLE);
|
||||||
|
app.setSettings(settings); |
||||||
|
app.start(); // start the game
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleInitApp() { |
||||||
|
initOpenCL1(); |
||||||
|
|
||||||
|
tex = new Texture2D(settings.getWidth(), settings.getHeight(), 1, com.jme3.texture.Image.Format.RGBA8); |
||||||
|
Picture pic = new Picture("julia"); |
||||||
|
pic.setTexture(assetManager, tex, true); |
||||||
|
pic.setPosition(0, 0); |
||||||
|
pic.setWidth(settings.getWidth()); |
||||||
|
pic.setHeight(settings.getHeight()); |
||||||
|
guiNode.attachChild(pic); |
||||||
|
|
||||||
|
initCounter = 0; |
||||||
|
|
||||||
|
flyCam.setEnabled(false); |
||||||
|
inputManager.setCursorVisible(true); |
||||||
|
inputManager.addMapping("right", new MouseAxisTrigger(MouseInput.AXIS_X, false)); |
||||||
|
inputManager.addMapping("left", new MouseAxisTrigger(MouseInput.AXIS_X, true)); |
||||||
|
inputManager.addMapping("up", new MouseAxisTrigger(MouseInput.AXIS_Y, false)); |
||||||
|
inputManager.addMapping("down", new MouseAxisTrigger(MouseInput.AXIS_Y, true)); |
||||||
|
inputManager.addMapping("drag", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); |
||||||
|
inputManager.addListener(this, "right", "left", "up", "down", "drag"); |
||||||
|
dragging = false; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleUpdate(float tpf) { |
||||||
|
super.simpleUpdate(tpf); |
||||||
|
|
||||||
|
if (initCounter < 2) { |
||||||
|
initCounter++; |
||||||
|
} else if (initCounter == 2) { |
||||||
|
//when initCounter reaches 2, the scene was drawn once and the texture was uploaded to the GPU
|
||||||
|
//then we can bind the texture to OpenCL
|
||||||
|
initOpenCL2(); |
||||||
|
updateOpenCL(tpf); |
||||||
|
initCounter = 3; |
||||||
|
} else { |
||||||
|
updateOpenCL(tpf); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private void initOpenCL1() { |
||||||
|
clContext = context.getOpenCLContext(); |
||||||
|
clQueue = clContext.createQueue(); |
||||||
|
clQueue.register(); |
||||||
|
programCache = new ProgramCache(clContext); |
||||||
|
//create kernel
|
||||||
|
String cacheID = getClass().getName()+".Julia"; |
||||||
|
Program program = programCache.loadFromCache(cacheID); |
||||||
|
if (program == null) { |
||||||
|
LOG.info("Program not loaded from cache, create from sources instead"); |
||||||
|
program = clContext.createProgramFromSourceFiles(assetManager, "jme3test/opencl/JuliaSet.cl"); |
||||||
|
program.build(); |
||||||
|
programCache.saveToCache(cacheID, program); |
||||||
|
} |
||||||
|
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.acquireImageForSharingNoEvent(clQueue); |
||||||
|
//no need to wait for the returned event, since the kernel implicitely waits for it (same command queue)
|
||||||
|
|
||||||
|
//execute kernel
|
||||||
|
Kernel.WorkSize ws = new Kernel.WorkSize(settings.getWidth(), settings.getHeight()); |
||||||
|
kernel.Run1NoEvent(clQueue, ws, texCL, C, 16); |
||||||
|
|
||||||
|
//release resource
|
||||||
|
texCL.releaseImageForSharingNoEvent(clQueue); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onAnalog(String name, float value, float tpf) { |
||||||
|
if (!dragging) { |
||||||
|
return; |
||||||
|
} |
||||||
|
if ("left".equals(name)) { |
||||||
|
C.x -= tpf * MOUSE_SPEED; |
||||||
|
} else if ("right".equals(name)) { |
||||||
|
C.x += tpf * MOUSE_SPEED; |
||||||
|
} else if ("up".equals(name)) { |
||||||
|
C.y -= tpf * MOUSE_SPEED; |
||||||
|
} else if ("down".equals(name)) { |
||||||
|
C.y += tpf * MOUSE_SPEED; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onAction(String name, boolean isPressed, float tpf) { |
||||||
|
if ("drag".equals(name)) { |
||||||
|
dragging = isPressed; |
||||||
|
inputManager.setCursorVisible(!isPressed); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,4 @@ |
|||||||
|
__kernel void Fill (__global TYPE* data, TYPE a) |
||||||
|
{ |
||||||
|
data[get_global_id(0)] = a; |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
||||||
|
<nifty xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xmlns="http://nifty-gui.lessvoid.com/nifty-gui" |
||||||
|
xsi:schemaLocation="https://raw.githubusercontent.com/void256/nifty-gui/1.4/nifty-core/src/main/resources/nifty.xsd https://raw.githubusercontent.com/void256/nifty-gui/1.4/nifty-core/src/main/resources/nifty.xsd"> |
||||||
|
|
||||||
|
<useStyles filename="nifty-default-styles.xml" /> |
||||||
|
<useControls filename="nifty-default-controls.xml" /> |
||||||
|
|
||||||
|
<screen id="Screen" controller="jme3test.opencl.TestContextSwitching"> |
||||||
|
<layer id="Layer0" childLayout="vertical"> |
||||||
|
<control name="label" id="InfoLabel" text="Current device:\n Platform: \n Device: \n Profile: \n Memory: \n Compute Units: " padding="10px" height="30%" /> |
||||||
|
<panel childLayout="horizontal" height="30%" > |
||||||
|
<panel childLayout="vertical" width="50%" > |
||||||
|
<control name="label" text="Select Platform" padding="10px"/> |
||||||
|
<control id="PlatformListBox" name="listBox" vertical="optional" horizontal="optional" displayItems="4" selection="Single" padding="10px" /> |
||||||
|
</panel> |
||||||
|
<panel childLayout="vertical" width="50%" > |
||||||
|
<control name="label" text="Select Device" padding="10px"/> |
||||||
|
<control id="DeviceListBox" name="listBox" vertical="optional" horizontal="optional" displayItems="4" selection="Single" padding="10px" /> |
||||||
|
</panel> |
||||||
|
</panel> |
||||||
|
<control name="button" id="ApplyButton" label="Change Context" align="center" valing="top" height="5%" padding="10px" /> |
||||||
|
<panel childLayout="center" height="30%" /> |
||||||
|
</layer> |
||||||
|
</screen> |
||||||
|
|
||||||
|
</nifty> |
@ -0,0 +1,99 @@ |
|||||||
|
|
||||||
|
|
||||||
|
//2 component vector to hold the real and imaginary parts of a complex number: |
||||||
|
typedef float2 cfloat; |
||||||
|
|
||||||
|
#define I ((cfloat)(0.0, 1.0)) |
||||||
|
|
||||||
|
inline float real(cfloat a){ |
||||||
|
return a.x; |
||||||
|
} |
||||||
|
inline float imag(cfloat a){ |
||||||
|
return a.y; |
||||||
|
} |
||||||
|
|
||||||
|
inline float cmod(cfloat a){ |
||||||
|
return (sqrt(a.x*a.x + a.y*a.y)); |
||||||
|
} |
||||||
|
|
||||||
|
inline cfloat cadd(cfloat a, cfloat b){ |
||||||
|
return (cfloat)( a.x + b.x, a.y + b.y); |
||||||
|
} |
||||||
|
|
||||||
|
inline float carg(cfloat a){ |
||||||
|
if(a.x > 0){ |
||||||
|
return atan(a.y / a.x); |
||||||
|
|
||||||
|
}else if(a.x < 0 && a.y >= 0){ |
||||||
|
return atan(a.y / a.x) + M_PI_F; |
||||||
|
|
||||||
|
}else if(a.x < 0 && a.y < 0){ |
||||||
|
return atan(a.y / a.x) - M_PI_F; |
||||||
|
|
||||||
|
}else if(a.x == 0 && a.y > 0){ |
||||||
|
return M_PI_F/2; |
||||||
|
|
||||||
|
}else if(a.x == 0 && a.y < 0){ |
||||||
|
return -M_PI_F/2; |
||||||
|
|
||||||
|
}else{ |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
inline cfloat cmult(cfloat a, cfloat b){ |
||||||
|
return (cfloat)( a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x); |
||||||
|
} |
||||||
|
|
||||||
|
inline cfloat csqrt(cfloat a){ |
||||||
|
return (cfloat)( sqrt(cmod(a)) * cos(carg(a)/2), sqrt(cmod(a)) * sin(carg(a)/2)); |
||||||
|
} |
||||||
|
|
||||||
|
inline float4 getColor(int iteration, int numIterations) { |
||||||
|
//color transition: black -> red -> blue -> white |
||||||
|
int step = numIterations / 2; |
||||||
|
if (iteration < step) { |
||||||
|
return mix( (float4)(0,0,0,1), (float4)(1,0,0,1), iteration / (float) step); |
||||||
|
} else { |
||||||
|
return mix( (float4)(1,0,0,1), (float4)(0,0,1,1), (iteration-step) / (float) (numIterations - step)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
__kernel void JuliaSet(write_only image2d_t outputImage, const cfloat C, int numIterations) |
||||||
|
{ |
||||||
|
// get id of element in array |
||||||
|
int x = get_global_id(0); |
||||||
|
int y = get_global_id(1); |
||||||
|
int w = get_global_size(0); |
||||||
|
int h = get_global_size(1); |
||||||
|
|
||||||
|
cfloat Z = { ( -w / 2 + x) / (w/4.0f) , ( -h / 2 + y) / (h/4.0f) }; |
||||||
|
int iteration = 0; |
||||||
|
|
||||||
|
while (iteration < numIterations) |
||||||
|
{ |
||||||
|
cfloat Zpow2 = cmult(Z, Z); |
||||||
|
cfloat Zn = cadd(Zpow2, C); |
||||||
|
Z.x = Zn.x; |
||||||
|
Z.y = Zn.y; |
||||||
|
iteration++; |
||||||
|
if(cmod(Z) > 2) |
||||||
|
{ |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
float4 color; |
||||||
|
|
||||||
|
// threshold reached mark pixel as white |
||||||
|
if (iteration == numIterations) |
||||||
|
{ |
||||||
|
color = (float4)(1,1,1,1); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
color = getColor(iteration, numIterations); |
||||||
|
} |
||||||
|
|
||||||
|
write_imagef(outputImage, (int2)(x, y), color); |
||||||
|
} |
@ -0,0 +1,236 @@ |
|||||||
|
/* |
||||||
|
* 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.jocl; |
||||||
|
|
||||||
|
import com.jme3.opencl.*; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import com.jogamp.opencl.*; |
||||||
|
import com.jogamp.opencl.llb.CL; |
||||||
|
import com.jogamp.opencl.llb.gl.CLGL; |
||||||
|
import java.util.EnumSet; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class JoclBuffer extends Buffer { |
||||||
|
|
||||||
|
final long id; |
||||||
|
final CL cl; |
||||||
|
|
||||||
|
public JoclBuffer(long id) { |
||||||
|
super(new ReleaserImpl(id)); |
||||||
|
this.id = id; |
||||||
|
this.cl = CLPlatform.getLowLevelCLInterface(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getSize() { |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
int ret = cl.clGetMemObjectInfo(id, CL.CL_MEM_SIZE, Utils.pointers[0].elementSize(), Utils.pointers[0].getBuffer(), null); |
||||||
|
Utils.checkError(ret, "clGetMemObjectInfo"); |
||||||
|
return Utils.pointers[0].get(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public MemoryAccess getMemoryAccessFlags() { |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
int ret = cl.clGetMemObjectInfo(id, CL.CL_MEM_TYPE, Utils.pointers[0].elementSize(), Utils.pointers[0].getBuffer(), null); |
||||||
|
Utils.checkError(ret, "clGetMemObjectInfo"); |
||||||
|
long flags = Utils.pointers[0].get(); |
||||||
|
return Utils.getMemoryAccessFromFlag(flags); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void read(CommandQueue queue, ByteBuffer dest, long size, long offset) { |
||||||
|
long q = ((JoclCommandQueue) queue).id; |
||||||
|
int ret = cl.clEnqueueReadBuffer(q, id, CL.CL_TRUE, offset, size, dest, 0, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueReadBuffer"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event readAsync(CommandQueue queue, ByteBuffer dest, long size, long offset) { |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
long q = ((JoclCommandQueue) queue).id; |
||||||
|
int ret = cl.clEnqueueReadBuffer(q, id, CL.CL_FALSE, offset, size, dest, 0, null, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueReadBuffer"); |
||||||
|
long event = Utils.pointers[0].get(0); |
||||||
|
return new JoclEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void write(CommandQueue queue, ByteBuffer src, long size, long offset) { |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
int ret = cl.clEnqueueWriteBuffer(q, id, CL.CL_TRUE, offset, size, src, 0, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueWriteBuffer"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event writeAsync(CommandQueue queue, ByteBuffer src, long size, long offset) { |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
int ret = cl.clEnqueueWriteBuffer(q, id, CL.CL_FALSE, offset, size, src, 0, null, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueWriteBuffer"); |
||||||
|
long event = Utils.pointers[0].get(0); |
||||||
|
return new JoclEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void copyTo(CommandQueue queue, Buffer dest, long size, long srcOffset, long destOffset) { |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
long did = ((JoclBuffer) dest).id; |
||||||
|
int ret = cl.clEnqueueCopyBuffer(q, id, did, srcOffset, destOffset, size, 0, null, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyBuffer"); |
||||||
|
ret = cl.clWaitForEvents(1, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clWaitForEvents"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event copyToAsync(CommandQueue queue, Buffer dest, long size, long srcOffset, long destOffset) { |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
long did = ((JoclBuffer) dest).id; |
||||||
|
int ret = cl.clEnqueueCopyBuffer(q, id, did, srcOffset, destOffset, size, 0, null, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyBuffer"); |
||||||
|
long event = Utils.pointers[0].get(0); |
||||||
|
return new JoclEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ByteBuffer map(CommandQueue queue, long size, long offset, MappingAccess access) { |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
long flags = Utils.getMappingAccessFlags(access); |
||||||
|
ByteBuffer b = cl.clEnqueueMapBuffer(q, id, CL.CL_TRUE, flags, offset, size, 0, null, null, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer"); |
||||||
|
return b; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void unmap(CommandQueue queue, ByteBuffer ptr) { |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
ptr.position(0); |
||||||
|
int ret = cl.clEnqueueUnmapMemObject(q, id, ptr, 0, null, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueUnmapMemObject"); |
||||||
|
ret = cl.clWaitForEvents(1, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clWaitForEvents"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public com.jme3.opencl.Buffer.AsyncMapping mapAsync(CommandQueue queue, long size, long offset, MappingAccess access) { |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
long flags = Utils.getMappingAccessFlags(access); |
||||||
|
ByteBuffer b = cl.clEnqueueMapBuffer(q, id, CL.CL_FALSE, flags, offset, size, 0, null, Utils.pointers[0], Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer"); |
||||||
|
long event = Utils.pointers[0].get(0); |
||||||
|
return new com.jme3.opencl.Buffer.AsyncMapping(new JoclEvent(event), b); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event fillAsync(CommandQueue queue, ByteBuffer pattern, long size, long offset) { |
||||||
|
throw new UnsupportedOperationException("Not supported by Jocl!"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event copyToImageAsync(CommandQueue queue, Image dest, long srcOffset, long[] destOrigin, long[] destRegion) { |
||||||
|
if (destOrigin.length!=3 || destRegion.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[2].rewind(); |
||||||
|
Utils.pointers[1].put(destOrigin[0]).put(destOrigin[1]).put(destOrigin[2]).position(0); |
||||||
|
Utils.pointers[2].put(destRegion[0]).put(destRegion[1]).put(destRegion[2]).position(0); |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
long i = ((JoclImage) dest).id; |
||||||
|
int ret = cl.clEnqueueCopyBufferToImage(q, id, i, srcOffset, Utils.pointers[1], Utils.pointers[2], 0, null, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyBufferToImage"); |
||||||
|
long event = Utils.pointers[0].get(0); |
||||||
|
return new JoclEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event acquireBufferForSharingAsync(CommandQueue queue) { |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[1].put(0, id); |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
((CLGL) cl).clEnqueueAcquireGLObjects(q, 1, Utils.pointers[1], 0, null, Utils.pointers[0]); |
||||||
|
long event = Utils.pointers[0].get(0); |
||||||
|
return new JoclEvent(event); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void acquireBufferForSharingNoEvent(CommandQueue queue) { |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[1].put(0, id); |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
((CLGL) cl).clEnqueueAcquireGLObjects(q, 1, Utils.pointers[1], 0, null, null); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event releaseBufferForSharingAsync(CommandQueue queue) { |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[1].put(0, id); |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
((CLGL) cl).clEnqueueReleaseGLObjects(q, 1, Utils.pointers[1], 0, null, Utils.pointers[0]); |
||||||
|
long event = Utils.pointers[0].get(0); |
||||||
|
return new JoclEvent(event); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void releaseBufferForSharingNoEvent(CommandQueue queue) { |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[1].put(0, id); |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
((CLGL) cl).clEnqueueReleaseGLObjects(q, 1, Utils.pointers[1], 0, null, null); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private long mem; |
||||||
|
private ReleaserImpl(long mem) { |
||||||
|
this.mem = mem; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (mem != 0) { |
||||||
|
int ret = CLPlatform.getLowLevelCLInterface().clReleaseMemObject(mem); |
||||||
|
mem = 0; |
||||||
|
Utils.reportError(ret, "clReleaseMemObject"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,84 @@ |
|||||||
|
/* |
||||||
|
* 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.jocl; |
||||||
|
|
||||||
|
import com.jme3.opencl.CommandQueue; |
||||||
|
import com.jme3.opencl.OpenCLObjectManager; |
||||||
|
import com.jogamp.opencl.CLCommandQueue; |
||||||
|
import com.jogamp.opencl.CLPlatform; |
||||||
|
import com.jogamp.opencl.llb.CL; |
||||||
|
import com.jogamp.opencl.llb.CLCommandQueueBinding; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
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(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void flush() { |
||||||
|
int ret = cl.clFlush(id); |
||||||
|
Utils.checkError(ret, "clFlush"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void finish() { |
||||||
|
int ret = cl.clFinish(id); |
||||||
|
Utils.checkError(ret, "clFinish"); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private long id; |
||||||
|
|
||||||
|
private ReleaserImpl(long id) { |
||||||
|
this.id = id; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (id != 0) { |
||||||
|
int ret = CLPlatform.getLowLevelCLInterface().clReleaseCommandQueue(id); |
||||||
|
id = 0; |
||||||
|
Utils.reportError(ret, "clReleaseCommandQueue"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,262 @@ |
|||||||
|
/* |
||||||
|
* 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.jocl; |
||||||
|
|
||||||
|
import com.jme3.opencl.*; |
||||||
|
import com.jme3.opencl.Context; |
||||||
|
import com.jme3.opencl.Image.ImageDescriptor; |
||||||
|
import com.jme3.opencl.Image.ImageFormat; |
||||||
|
import com.jme3.scene.VertexBuffer; |
||||||
|
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.Mem; |
||||||
|
import com.jogamp.opencl.CLPlatform; |
||||||
|
import com.jogamp.opencl.llb.CL; |
||||||
|
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.util.List; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class JoclContext extends Context { |
||||||
|
private static final Logger LOG = Logger.getLogger(JoclContext.class.getName()); |
||||||
|
|
||||||
|
final CLContext context; |
||||||
|
final long id; |
||||||
|
final CL cl; |
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
public CLContext getContext() { |
||||||
|
return context; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<JoclDevice> getDevices() { |
||||||
|
return devices; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
@SuppressWarnings("element-type-mismatch") |
||||||
|
public CommandQueue createQueue(Device device) { |
||||||
|
assert (devices.contains(device)); //this also ensures that device is a JoclDevice
|
||||||
|
long d = ((JoclDevice) device).id; |
||||||
|
long properties = 0; |
||||||
|
long q = cl.clCreateCommandQueue(id, d, properties, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateCommandQueue"); |
||||||
|
return new JoclCommandQueue(q); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Buffer createBuffer(long size, MemoryAccess access) { |
||||||
|
long flags = Utils.getMemoryAccessFlags(access); |
||||||
|
long mem = cl.clCreateBuffer(id, flags, size, null, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateBuffer"); |
||||||
|
return new JoclBuffer(mem); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Buffer createBufferFromHost(ByteBuffer data, MemoryAccess access) { |
||||||
|
long flags = Utils.getMemoryAccessFlags(access); |
||||||
|
flags |= CL.CL_MEM_USE_HOST_PTR; |
||||||
|
long mem = cl.clCreateBuffer(id, flags, data.capacity(), data, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateBuffer"); |
||||||
|
return new JoclBuffer(mem); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Image createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr) { |
||||||
|
if (descr.type != Image.ImageType.IMAGE_2D && descr.type != Image.ImageType.IMAGE_3D) { |
||||||
|
throw new UnsupportedOperationException("Jocl only supports 2D and 3D images"); |
||||||
|
} |
||||||
|
long memFlags = Utils.getMemoryAccessFlags(access); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
//fill image format
|
||||||
|
CLImageFormatImpl f = CLImageFormatImpl.create(); |
||||||
|
f.setImageChannelOrder(JoclImage.decodeImageChannelOrder(format.channelOrder)); |
||||||
|
f.setImageChannelDataType(JoclImage.decodeImageChannelType(format.channelType)); |
||||||
|
//create image
|
||||||
|
long mem; |
||||||
|
if (descr.type == Image.ImageType.IMAGE_2D) { |
||||||
|
mem = cl.clCreateImage2D(id, memFlags, f, descr.width, descr.height, |
||||||
|
descr.hostPtr==null ? 0 : descr.rowPitch, descr.hostPtr, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateImage2D"); |
||||||
|
} else { |
||||||
|
mem = cl.clCreateImage3D(id, memFlags, f, descr.width, descr.height, descr.depth, |
||||||
|
descr.hostPtr==null ? 0 : descr.rowPitch, descr.hostPtr==null ? 0 : descr.slicePitch, |
||||||
|
descr.hostPtr, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateImage3D"); |
||||||
|
} |
||||||
|
return new JoclImage(mem); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageFormat[] querySupportedFormats(MemoryAccess access, Image.ImageType type) { |
||||||
|
if (type != Image.ImageType.IMAGE_2D && type != Image.ImageType.IMAGE_3D) { |
||||||
|
throw new UnsupportedOperationException("Jocl only supports 2D and 3D images"); |
||||||
|
} |
||||||
|
long memFlags = Utils.getMemoryAccessFlags(access); |
||||||
|
CLImageFormat[] fx; |
||||||
|
if (type == Image.ImageType.IMAGE_2D) { |
||||||
|
fx = context.getSupportedImage2dFormats(Mem.valueOf((int) memFlags)); |
||||||
|
} else { |
||||||
|
fx = context.getSupportedImage3dFormats(Mem.valueOf((int) memFlags)); |
||||||
|
} |
||||||
|
//convert formats
|
||||||
|
ImageFormat[] formats = new ImageFormat[fx.length]; |
||||||
|
for (int i=0; i<fx.length; ++i) { |
||||||
|
Image.ImageChannelOrder channelOrder = JoclImage.encodeImageChannelOrder(fx[i].getFormatImpl().getImageChannelOrder()); |
||||||
|
Image.ImageChannelType channelType = JoclImage.encodeImageChannelType(fx[i].getFormatImpl().getImageChannelDataType()); |
||||||
|
formats[i] = new ImageFormat(channelOrder, channelType); |
||||||
|
} |
||||||
|
return formats; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Buffer bindVertexBuffer(VertexBuffer vb, MemoryAccess access) { |
||||||
|
int vbId = vb.getId(); |
||||||
|
if (vbId == -1) { |
||||||
|
throw new IllegalArgumentException("vertex buffer was not yet uploaded to the GPU or is CPU only"); |
||||||
|
} |
||||||
|
long flags = Utils.getMemoryAccessFlags(access); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
long mem = ((CLGL) cl).clCreateFromGLBuffer(id, flags, vbId, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateFromGLBuffer"); |
||||||
|
return new JoclBuffer(mem); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Image bindImage(com.jme3.texture.Image image, Texture.Type textureType, int miplevel, MemoryAccess access) { |
||||||
|
int imageID = image.getId(); |
||||||
|
if (imageID == -1) { |
||||||
|
throw new IllegalArgumentException("image was not yet uploaded to the GPU"); |
||||||
|
} |
||||||
|
long memFlags = Utils.getMemoryAccessFlags(access); |
||||||
|
int textureTarget = convertTextureType(textureType); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
long mem; |
||||||
|
if (textureType == Texture.Type.TwoDimensional) { |
||||||
|
mem = ((CLGL) cl).clCreateFromGLTexture2D(id, memFlags, textureTarget, miplevel, imageID, Utils.errorBuffer); |
||||||
|
} else if (textureType == Texture.Type.ThreeDimensional) { |
||||||
|
mem = ((CLGL) cl).clCreateFromGLTexture3D(id, memFlags, textureTarget, miplevel, imageID, Utils.errorBuffer); |
||||||
|
} else { |
||||||
|
throw new UnsupportedOperationException("Jocl only supports 2D and 3D images"); |
||||||
|
} |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateFromGLTexture"); |
||||||
|
return new JoclImage(mem); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Image bindPureRenderBuffer(FrameBuffer.RenderBuffer buffer, MemoryAccess access) { |
||||||
|
int renderbuffer = buffer.getId(); |
||||||
|
if (renderbuffer == -1) { |
||||||
|
throw new IllegalArgumentException("renderbuffer was not yet uploaded to the GPU"); |
||||||
|
} |
||||||
|
long memFlags = Utils.getMemoryAccessFlags(access); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
long mem = ((CLGL) cl).clCreateFromGLRenderbuffer(id, memFlags, renderbuffer, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateFromGLRenderbuffer"); |
||||||
|
return new JoclImage(mem); |
||||||
|
} |
||||||
|
|
||||||
|
private int convertTextureType(Texture.Type textureType) { |
||||||
|
switch (textureType) { |
||||||
|
case TwoDimensional: return GL.GL_TEXTURE_2D; |
||||||
|
case CubeMap: return GL.GL_TEXTURE_CUBE_MAP; |
||||||
|
default: throw new IllegalArgumentException("unknown or unsupported texture type "+textureType); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Program createProgramFromSourceCode(String sourceCode) { |
||||||
|
LOG.log(Level.FINE, "Create program from source:\n{0}", sourceCode); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.pointers[0].put(0, sourceCode.length()); |
||||||
|
long p = cl.clCreateProgramWithSource(id, 1, new String[]{sourceCode}, Utils.pointers[0], Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateProgramWithSource"); |
||||||
|
return new JoclProgram(p, this); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Program createProgramFromBinary(ByteBuffer binaries, Device device) { |
||||||
|
binaries.rewind(); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
Utils.tempBuffers[0].b16i.rewind(); |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.pointers[0].put(0, ((JoclDevice) device).id); |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[1].put(0, binaries.remaining()); |
||||||
|
Utils.pointers[2].rewind(); |
||||||
|
Utils.pointers[2].referenceBuffer(0, binaries); |
||||||
|
long p = cl.clCreateProgramWithBinary(id, 1, Utils.pointers[0], |
||||||
|
Utils.pointers[1], Utils.pointers[2], Utils.tempBuffers[0].b16i, |
||||||
|
Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateProgramWithBinary"); |
||||||
|
Utils.checkError(Utils.tempBuffers[0].b16i, "clCreateProgramWithBinary"); |
||||||
|
return new JoclProgram(p, this); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private long id; |
||||||
|
private final List<JoclDevice> devices; |
||||||
|
private ReleaserImpl(long id, List<JoclDevice> devices) { |
||||||
|
this.id = id; |
||||||
|
this.devices = devices; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (id != 0) { |
||||||
|
int ret = CLPlatform.getLowLevelCLInterface().clReleaseContext(id); |
||||||
|
id = 0; |
||||||
|
devices.clear(); |
||||||
|
Utils.reportError(ret, "clReleaseContext"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,302 @@ |
|||||||
|
/* |
||||||
|
* 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.jocl; |
||||||
|
|
||||||
|
import com.jme3.opencl.Device; |
||||||
|
import com.jme3.opencl.Platform; |
||||||
|
import com.jogamp.opencl.CLDevice; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Collection; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public final class JoclDevice implements Device { |
||||||
|
|
||||||
|
final long id; |
||||||
|
final CLDevice device; |
||||||
|
final JoclPlatform platform; |
||||||
|
|
||||||
|
public JoclDevice(CLDevice device, JoclPlatform platform) { |
||||||
|
this.id = device.ID; |
||||||
|
this.device = device; |
||||||
|
this.platform = platform; |
||||||
|
} |
||||||
|
|
||||||
|
public long getId() { |
||||||
|
return id; |
||||||
|
} |
||||||
|
|
||||||
|
public CLDevice getDevice() { |
||||||
|
return device; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public JoclPlatform getPlatform() { |
||||||
|
return platform; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public DeviceType getDeviceType() { |
||||||
|
CLDevice.Type type = device.getType(); |
||||||
|
switch (type) { |
||||||
|
case ACCELERATOR: return DeviceType.ACCELEARTOR; |
||||||
|
case CPU: return DeviceType.CPU; |
||||||
|
case GPU: return DeviceType.GPU; |
||||||
|
default: return DeviceType.DEFAULT; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getVendorId() { |
||||||
|
return (int) device.getVendorID(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isAvailable() { |
||||||
|
return device.isAvailable(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasCompiler() { |
||||||
|
return device.isCompilerAvailable(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasDouble() { |
||||||
|
return hasExtension("cl_khr_fp64"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasHalfFloat() { |
||||||
|
return hasExtension("cl_khr_fp16"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasErrorCorrectingMemory() { |
||||||
|
return device.isErrorCorrectionSupported(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasUnifiedMemory() { |
||||||
|
return device.isMemoryUnified(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasImageSupport() { |
||||||
|
return device.isImageSupportAvailable(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasWritableImage3D() { |
||||||
|
return hasExtension("cl_khr_3d_image_writes"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasOpenGLInterop() { |
||||||
|
return hasExtension("cl_khr_gl_sharing"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasExtension(String extension) { |
||||||
|
return getExtensions().contains(extension); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Collection<? extends String> getExtensions() { |
||||||
|
return device.getExtensions(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getComputeUnits() { |
||||||
|
return device.getMaxComputeUnits(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getClockFrequency() { |
||||||
|
return device.getMaxClockFrequency(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getAddressBits() { |
||||||
|
return device.getAddressBits(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isLittleEndian() { |
||||||
|
return device.isLittleEndian(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaximumWorkItemDimensions() { |
||||||
|
return device.getMaxWorkItemDimensions(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long[] getMaximumWorkItemSizes() { |
||||||
|
int[] sizes = device.getMaxWorkItemSizes(); |
||||||
|
long[] s = new long[sizes.length]; |
||||||
|
for (int i=0; i<sizes.length; ++i) { |
||||||
|
s[i] = sizes[i]; |
||||||
|
} |
||||||
|
return s; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaxiumWorkItemsPerGroup() { |
||||||
|
return device.getMaxWorkGroupSize(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getMaximumSamplers() { |
||||||
|
return device.getMaxSamplers(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getMaximumReadImages() { |
||||||
|
return device.getMaxReadImageArgs(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getMaximumWriteImages() { |
||||||
|
return device.getMaxWriteImageArgs(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long[] getMaximumImage2DSize() { |
||||||
|
return new long[] { |
||||||
|
device.getMaxImage2dWidth(), |
||||||
|
device.getMaxImage2dHeight() |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long[] getMaximumImage3DSize() { |
||||||
|
return new long[] { |
||||||
|
device.getMaxImage3dWidth(), |
||||||
|
device.getMaxImage3dHeight(), |
||||||
|
device.getMaxImage3dDepth() |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaximumAllocationSize() { |
||||||
|
return device.getMaxMemAllocSize(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getGlobalMemorySize() { |
||||||
|
return device.getGlobalMemSize(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getLocalMemorySize() { |
||||||
|
return device.getLocalMemSize(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaximumConstantBufferSize() { |
||||||
|
return device.getMaxConstantBufferSize(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getMaximumConstantArguments() { |
||||||
|
return (int) device.getMaxConstantArgs(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getProfile() { |
||||||
|
return device.getProfile(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getVersion() { |
||||||
|
return device.getVersion().toString(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getVersionMajor() { |
||||||
|
return Utils.getMajorVersion(getVersion(), "OpenCL "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getVersionMinor() { |
||||||
|
return Utils.getMinorVersion(getVersion(), "OpenCL "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getCompilerVersion() { |
||||||
|
return "OpenCL C 1.1"; //at most OpenCL 1.1 is supported at all
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getCompilerVersionMajor() { |
||||||
|
return Utils.getMajorVersion(getCompilerVersion(), "OpenCL C "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getCompilerVersionMinor() { |
||||||
|
return Utils.getMinorVersion(getCompilerVersion(), "OpenCL C "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getDriverVersion() { |
||||||
|
return device.getDriverVersion(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getDriverVersionMajor() { |
||||||
|
return Utils.getMajorVersion(getDriverVersion(), ""); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getDriverVersionMinor() { |
||||||
|
return Utils.getMinorVersion(getDriverVersion(), ""); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return device.getName(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getVendor() { |
||||||
|
return device.getVendor(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return getName(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,100 @@ |
|||||||
|
/* |
||||||
|
* 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.jocl; |
||||||
|
|
||||||
|
import com.jme3.opencl.Event; |
||||||
|
import com.jme3.opencl.OpenCLObjectManager; |
||||||
|
import com.jogamp.opencl.CLPlatform; |
||||||
|
import com.jogamp.opencl.llb.CL; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
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(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void waitForFinished() { |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.pointers[0].put(0, id); |
||||||
|
int ret = cl.clWaitForEvents(1, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clWaitForEvents"); |
||||||
|
release(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isCompleted() { |
||||||
|
Utils.tempBuffers[0].b16.rewind(); |
||||||
|
int err = cl.clGetEventInfo(id, CL.CL_EVENT_COMMAND_EXECUTION_STATUS, 4, Utils.tempBuffers[0].b16, null); |
||||||
|
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"); |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private long event; |
||||||
|
|
||||||
|
private ReleaserImpl(long event) { |
||||||
|
this.event = event; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (event != 0) { |
||||||
|
int ret = CLPlatform.getLowLevelCLInterface().clReleaseEvent(event); |
||||||
|
event = 0; |
||||||
|
Utils.reportError(ret, "clReleaseEvent"); |
||||||
|
LOG.finer("Event deleted"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,544 @@ |
|||||||
|
/* |
||||||
|
* 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.jocl; |
||||||
|
|
||||||
|
import com.jme3.math.ColorRGBA; |
||||||
|
import com.jme3.opencl.*; |
||||||
|
import com.jogamp.opencl.CLPlatform; |
||||||
|
import com.jogamp.opencl.llb.CL; |
||||||
|
import com.jogamp.opencl.llb.gl.CLGL; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
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(); |
||||||
|
} |
||||||
|
|
||||||
|
public static int decodeImageChannelOrder(ImageChannelOrder order) { |
||||||
|
switch (order) { |
||||||
|
case A: |
||||||
|
return CL.CL_A; |
||||||
|
case ARGB: |
||||||
|
return CL.CL_ARGB; |
||||||
|
case BGRA: |
||||||
|
return CL.CL_BGRA; |
||||||
|
case INTENSITY: |
||||||
|
return CL.CL_INTENSITY; |
||||||
|
case LUMINANCE: |
||||||
|
return CL.CL_LUMINANCE; |
||||||
|
case R: |
||||||
|
return CL.CL_R; |
||||||
|
case RA: |
||||||
|
return CL.CL_RA; |
||||||
|
case RG: |
||||||
|
return CL.CL_RG; |
||||||
|
case RGB: |
||||||
|
return CL.CL_RGB; |
||||||
|
case RGBA: |
||||||
|
return CL.CL_RGBA; |
||||||
|
case RGBx: |
||||||
|
return CL.CL_RGBx; |
||||||
|
case RGx: |
||||||
|
return CL.CL_RGx; |
||||||
|
case Rx: |
||||||
|
return CL.CL_Rx; |
||||||
|
default: |
||||||
|
throw new IllegalArgumentException("unknown image channel order: " + order); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static ImageChannelOrder encodeImageChannelOrder(int order) { |
||||||
|
switch (order) { |
||||||
|
case CL.CL_A: |
||||||
|
return ImageChannelOrder.A; |
||||||
|
case CL.CL_ARGB: |
||||||
|
return ImageChannelOrder.ARGB; |
||||||
|
case CL.CL_BGRA: |
||||||
|
return ImageChannelOrder.BGRA; |
||||||
|
case CL.CL_INTENSITY: |
||||||
|
return ImageChannelOrder.INTENSITY; |
||||||
|
case CL.CL_LUMINANCE: |
||||||
|
return ImageChannelOrder.LUMINANCE; |
||||||
|
case CL.CL_R: |
||||||
|
return ImageChannelOrder.R; |
||||||
|
case CL.CL_RA: |
||||||
|
return ImageChannelOrder.RA; |
||||||
|
case CL.CL_RG: |
||||||
|
return ImageChannelOrder.RG; |
||||||
|
case CL.CL_RGB: |
||||||
|
return ImageChannelOrder.RGB; |
||||||
|
case CL.CL_RGBA: |
||||||
|
return ImageChannelOrder.RGBA; |
||||||
|
case CL.CL_RGBx: |
||||||
|
return ImageChannelOrder.RGBx; |
||||||
|
case CL.CL_RGx: |
||||||
|
return ImageChannelOrder.RGx; |
||||||
|
case CL.CL_Rx: |
||||||
|
return ImageChannelOrder.Rx; |
||||||
|
default: |
||||||
|
//throw new com.jme3.opencl.OpenCLException("unknown image channel order id: " + order);
|
||||||
|
LOG.log(Level.WARNING, "Unknown image channel order id: {0}", order); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static int decodeImageChannelType(ImageChannelType type) { |
||||||
|
switch (type) { |
||||||
|
case FLOAT: |
||||||
|
return CL.CL_FLOAT; |
||||||
|
case HALF_FLOAT: |
||||||
|
return CL.CL_HALF_FLOAT; |
||||||
|
case SIGNED_INT16: |
||||||
|
return CL.CL_SIGNED_INT16; |
||||||
|
case SIGNED_INT32: |
||||||
|
return CL.CL_SIGNED_INT32; |
||||||
|
case SIGNED_INT8: |
||||||
|
return CL.CL_SIGNED_INT8; |
||||||
|
case SNORM_INT16: |
||||||
|
return CL.CL_SNORM_INT16; |
||||||
|
case SNORM_INT8: |
||||||
|
return CL.CL_SNORM_INT8; |
||||||
|
case UNORM_INT8: |
||||||
|
return CL.CL_UNORM_INT8; |
||||||
|
case UNORM_INT_101010: |
||||||
|
return CL.CL_UNORM_INT_101010; |
||||||
|
case UNORM_INT16: |
||||||
|
return CL.CL_UNORM_INT16; |
||||||
|
case UNORM_SHORT_565: |
||||||
|
return CL.CL_UNORM_SHORT_565; |
||||||
|
case UNORM_SHORT_555: |
||||||
|
return CL.CL_UNORM_SHORT_555; |
||||||
|
case UNSIGNED_INT16: |
||||||
|
return CL.CL_UNSIGNED_INT16; |
||||||
|
case UNSIGNED_INT32: |
||||||
|
return CL.CL_UNSIGNED_INT32; |
||||||
|
case UNSIGNED_INT8: |
||||||
|
return CL.CL_UNSIGNED_INT8; |
||||||
|
default: |
||||||
|
throw new IllegalArgumentException("Unknown image channel type: " + type); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static ImageChannelType encodeImageChannelType(int type) { |
||||||
|
switch (type) { |
||||||
|
case CL.CL_FLOAT: |
||||||
|
return ImageChannelType.FLOAT; |
||||||
|
case CL.CL_HALF_FLOAT: |
||||||
|
return ImageChannelType.HALF_FLOAT; |
||||||
|
case CL.CL_SIGNED_INT16: |
||||||
|
return ImageChannelType.SIGNED_INT16; |
||||||
|
case CL.CL_SIGNED_INT32: |
||||||
|
return ImageChannelType.SIGNED_INT32; |
||||||
|
case CL.CL_SIGNED_INT8: |
||||||
|
return ImageChannelType.SIGNED_INT8; |
||||||
|
case CL.CL_SNORM_INT16: |
||||||
|
return ImageChannelType.SNORM_INT16; |
||||||
|
case CL.CL_SNORM_INT8: |
||||||
|
return ImageChannelType.SNORM_INT8; |
||||||
|
case CL.CL_UNORM_INT8: |
||||||
|
return ImageChannelType.UNORM_INT8; |
||||||
|
case CL.CL_UNORM_INT16: |
||||||
|
return ImageChannelType.UNORM_INT16; |
||||||
|
case CL.CL_UNORM_INT_101010: |
||||||
|
return ImageChannelType.UNORM_INT_101010; |
||||||
|
case CL.CL_UNORM_SHORT_555: |
||||||
|
return ImageChannelType.UNORM_SHORT_555; |
||||||
|
case CL.CL_UNORM_SHORT_565: |
||||||
|
return ImageChannelType.UNORM_SHORT_565; |
||||||
|
case CL.CL_UNSIGNED_INT16: |
||||||
|
return ImageChannelType.UNSIGNED_INT16; |
||||||
|
case CL.CL_UNSIGNED_INT32: |
||||||
|
return ImageChannelType.UNSIGNED_INT32; |
||||||
|
case CL.CL_UNSIGNED_INT8: |
||||||
|
return ImageChannelType.UNSIGNED_INT8; |
||||||
|
default: |
||||||
|
//throw new com.jme3.opencl.OpenCLException("unknown image channel type id: " + type);
|
||||||
|
LOG.log(Level.WARNING, "Unknown image channel type id: {0}", type); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static int decodeImageType(ImageType type) { |
||||||
|
switch (type) { |
||||||
|
// case IMAGE_1D:
|
||||||
|
// return CL.CL_MEM_OBJECT_IMAGE1D;
|
||||||
|
// case IMAGE_1D_ARRAY:
|
||||||
|
// return CL.CL_MEM_OBJECT_IMAGE1D_ARRAY;
|
||||||
|
// case IMAGE_1D_BUFFER:
|
||||||
|
// return CL.CL_MEM_OBJECT_IMAGE1D_BUFFER;
|
||||||
|
case IMAGE_2D: |
||||||
|
return CL.CL_MEM_OBJECT_IMAGE2D; |
||||||
|
// case IMAGE_2D_ARRAY:
|
||||||
|
// return CL.CL_MEM_OBJECT_IMAGE2D_ARRAY;
|
||||||
|
case IMAGE_3D: |
||||||
|
return CL.CL_MEM_OBJECT_IMAGE3D; |
||||||
|
default: |
||||||
|
throw new IllegalArgumentException("Unknown or unsupported image type: " + type); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static ImageType encodeImageType(int type) { |
||||||
|
switch (type) { |
||||||
|
// case CL12.CL_MEM_OBJECT_IMAGE1D:
|
||||||
|
// return ImageType.IMAGE_1D;
|
||||||
|
// case CL12.CL_MEM_OBJECT_IMAGE1D_ARRAY:
|
||||||
|
// return ImageType.IMAGE_1D_ARRAY;
|
||||||
|
// case CL12.CL_MEM_OBJECT_IMAGE1D_BUFFER:
|
||||||
|
// return ImageType.IMAGE_1D_BUFFER;
|
||||||
|
case CL.CL_MEM_OBJECT_IMAGE2D: |
||||||
|
return ImageType.IMAGE_2D; |
||||||
|
// case CL12.CL_MEM_OBJECT_IMAGE2D_ARRAY:
|
||||||
|
// return ImageType.IMAGE_2D_ARRAY;
|
||||||
|
case CL.CL_MEM_OBJECT_IMAGE3D: |
||||||
|
return ImageType.IMAGE_3D; |
||||||
|
default: |
||||||
|
//throw new com.jme3.opencl.OpenCLException("Unknown image type id: " + type);
|
||||||
|
LOG.log(Level.WARNING, "Unknown or unsupported image type with id: {0}", type); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private long getInfoSize(int param) { |
||||||
|
Utils.tempBuffers[0].b16l.rewind(); |
||||||
|
int ret = cl.clGetImageInfo(id, param, 8, Utils.tempBuffers[0].b16l, null); |
||||||
|
Utils.checkError(ret, "clGetImageInfo"); |
||||||
|
return Utils.tempBuffers[0].b16l.get(0); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getWidth() { |
||||||
|
return getInfoSize(CL.CL_IMAGE_WIDTH); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getHeight() { |
||||||
|
return getInfoSize(CL.CL_IMAGE_HEIGHT); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getDepth() { |
||||||
|
return getInfoSize(CL.CL_IMAGE_DEPTH); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getRowPitch() { |
||||||
|
return getInfoSize(CL.CL_IMAGE_ROW_PITCH); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getSlicePitch() { |
||||||
|
return getInfoSize(CL.CL_IMAGE_SLICE_PITCH); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getArraySize() { |
||||||
|
//return getInfoSize(CL12.CL_IMAGE_ARRAY_SIZE);
|
||||||
|
throw new UnsupportedOperationException("Not supported in Jocl"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageFormat getImageFormat() { |
||||||
|
Utils.tempBuffers[0].b16i.rewind(); |
||||||
|
int ret = cl.clGetImageInfo(id, CL.CL_IMAGE_FORMAT, 8, Utils.tempBuffers[0].b16i, null); |
||||||
|
Utils.checkError(ret, "clGetImageInfo"); |
||||||
|
int channelOrder = Utils.tempBuffers[0].b16i.get(0); |
||||||
|
int channelType = Utils.tempBuffers[0].b16i.get(1); |
||||||
|
return new ImageFormat(encodeImageChannelOrder(channelOrder), encodeImageChannelType(channelType)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageType getImageType() { |
||||||
|
Utils.tempBuffers[0].b16i.rewind(); |
||||||
|
int ret = cl.clGetMemObjectInfo(id, CL.CL_IMAGE_FORMAT, 5, Utils.tempBuffers[0].b16i, null); |
||||||
|
int type = Utils.tempBuffers[0].b16i.get(0); |
||||||
|
return encodeImageType(type); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getElementSize() { |
||||||
|
return (int) getInfoSize(CL.CL_IMAGE_ELEMENT_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void readImage(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[2].rewind(); |
||||||
|
Utils.pointers[1].put(origin, 0, 3).position(0); |
||||||
|
Utils.pointers[2].put(region, 0, 3).position(0); |
||||||
|
long q = ((JoclCommandQueue) queue).id; |
||||||
|
int ret = cl.clEnqueueReadImage(q, id, CL.CL_TRUE, Utils.pointers[1], Utils.pointers[2], rowPitch, slicePitch, dest, 0, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueReadImage"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event readImageAsync(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[2].rewind(); |
||||||
|
Utils.pointers[1].put(origin, 0, 3).position(0); |
||||||
|
Utils.pointers[2].put(region, 0, 3).position(0); |
||||||
|
long q = ((JoclCommandQueue) queue).id; |
||||||
|
int ret = cl.clEnqueueReadImage(q, id, CL.CL_FALSE, Utils.pointers[1], Utils.pointers[2], rowPitch, slicePitch, dest, 0, null, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueReadImage"); |
||||||
|
long event = Utils.pointers[0].get(0); |
||||||
|
return new JoclEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void writeImage(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[2].rewind(); |
||||||
|
Utils.pointers[1].put(origin, 0, 3).position(0); |
||||||
|
Utils.pointers[2].put(region, 0, 3).position(0); |
||||||
|
long q = ((JoclCommandQueue) queue).id; |
||||||
|
int ret = cl.clEnqueueWriteImage(q, id, CL.CL_TRUE, Utils.pointers[1], Utils.pointers[2], rowPitch, slicePitch, dest, 0, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueWriteImage"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event writeImageAsync(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[2].rewind(); |
||||||
|
Utils.pointers[1].put(origin, 0, 3).position(0); |
||||||
|
Utils.pointers[2].put(region, 0, 3).position(0); |
||||||
|
long q = ((JoclCommandQueue) queue).id; |
||||||
|
int ret = cl.clEnqueueWriteImage(q, id, CL.CL_FALSE, Utils.pointers[1], Utils.pointers[2], rowPitch, slicePitch, dest, 0, null, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueWriteImage"); |
||||||
|
long event = Utils.pointers[0].get(0); |
||||||
|
return new JoclEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void copyTo(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region) { |
||||||
|
if (srcOrigin.length!=3 || destOrigin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[2].rewind(); |
||||||
|
Utils.pointers[3].rewind(); |
||||||
|
Utils.pointers[1].put(srcOrigin, 0, 3).position(0); |
||||||
|
Utils.pointers[2].put(destOrigin, 0, 3).position(0); |
||||||
|
Utils.pointers[3].put(region, 0, 3).position(0); |
||||||
|
long q = ((JoclCommandQueue) queue).id; |
||||||
|
int ret = cl.clEnqueueCopyImage(q, id, ((JoclImage) dest).id, Utils.pointers[1], Utils.pointers[2], Utils.pointers[3], 0, null, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyImage"); |
||||||
|
ret = cl.clWaitForEvents(1, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clWaitForEvents"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event copyToAsync(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region) { |
||||||
|
if (srcOrigin.length!=3 || destOrigin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[2].rewind(); |
||||||
|
Utils.pointers[3].rewind(); |
||||||
|
Utils.pointers[1].put(srcOrigin, 0, 3).position(0); |
||||||
|
Utils.pointers[2].put(destOrigin, 0, 3).position(0); |
||||||
|
Utils.pointers[3].put(region, 0, 3).position(0); |
||||||
|
long q = ((JoclCommandQueue) queue).id; |
||||||
|
int ret = cl.clEnqueueCopyImage(q, id, ((JoclImage) dest).id, Utils.pointers[1], Utils.pointers[2], Utils.pointers[3], 0, null, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyImage"); |
||||||
|
long event = Utils.pointers[0].get(0); |
||||||
|
return new JoclEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageMapping map(CommandQueue queue, long[] origin, long[] region, MappingAccess access) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[2].rewind(); |
||||||
|
Utils.pointers[3].rewind(); |
||||||
|
Utils.pointers[4].rewind(); |
||||||
|
Utils.pointers[1].put(origin, 0, 3).position(0); |
||||||
|
Utils.pointers[2].put(region, 0, 3).position(0); |
||||||
|
long q = ((JoclCommandQueue) queue).id; |
||||||
|
long flags = Utils.getMappingAccessFlags(access); |
||||||
|
ByteBuffer buf = cl.clEnqueueMapImage(q, id, CL.CL_TRUE, flags, Utils.pointers[1], Utils.pointers[2], |
||||||
|
Utils.pointers[3], Utils.pointers[4], 0, null, null, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer"); |
||||||
|
return new ImageMapping(buf, Utils.pointers[3].get(0), Utils.pointers[4].get(0)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageMapping mapAsync(CommandQueue queue, long[] origin, long[] region, MappingAccess access) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[2].rewind(); |
||||||
|
Utils.pointers[3].rewind(); |
||||||
|
Utils.pointers[4].rewind(); |
||||||
|
Utils.pointers[1].put(origin, 0, 3).position(0); |
||||||
|
Utils.pointers[2].put(region, 0, 3).position(0); |
||||||
|
long q = ((JoclCommandQueue) queue).id; |
||||||
|
long flags = Utils.getMappingAccessFlags(access); |
||||||
|
ByteBuffer buf = cl.clEnqueueMapImage(q, id, CL.CL_FALSE, flags, Utils.pointers[1], Utils.pointers[2], |
||||||
|
Utils.pointers[3], Utils.pointers[4], 0, null, Utils.pointers[0], Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer"); |
||||||
|
long event = Utils.pointers[0].get(0); |
||||||
|
return new ImageMapping(buf, Utils.pointers[3].get(0), Utils.pointers[4].get(0), |
||||||
|
new JoclEvent(event)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void unmap(CommandQueue queue, ImageMapping mapping) { |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
mapping.buffer.position(0); |
||||||
|
int ret = cl.clEnqueueUnmapMemObject(q, id, mapping.buffer, 0, null, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueUnmapMemObject"); |
||||||
|
ret = cl.clWaitForEvents(1, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clWaitForEvents"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event fillAsync(CommandQueue queue, long[] origin, long[] region, ColorRGBA color) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
throw new UnsupportedOperationException("Not supported by Jocl!"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event fillAsync(CommandQueue queue, long[] origin, long[] region, int[] color) { |
||||||
|
if (color.length != 4) { |
||||||
|
throw new IllegalArgumentException("the passed color array must have length 4"); |
||||||
|
} |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
throw new UnsupportedOperationException("Not supported by Jocl!"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event copyToBufferAsync(CommandQueue queue, Buffer dest, long[] srcOrigin, long[] srcRegion, long destOffset) { |
||||||
|
if (srcOrigin.length!=3 || srcRegion.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[2].rewind(); |
||||||
|
Utils.pointers[1].put(srcOrigin, 0, 3).position(0); |
||||||
|
Utils.pointers[2].put(srcRegion, 0, 3).position(0); |
||||||
|
long q = ((JoclCommandQueue) queue).id; |
||||||
|
int ret = cl.clEnqueueCopyImageToBuffer(q, id, ((JoclBuffer) dest).id, |
||||||
|
Utils.pointers[1], Utils.pointers[2], destOffset, 0, null, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyImageToBuffer"); |
||||||
|
long event = Utils.pointers[0].get(0); |
||||||
|
return new JoclEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event acquireImageForSharingAsync(CommandQueue queue) { |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[1].put(0, id); |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
((CLGL) cl).clEnqueueAcquireGLObjects(q, 1, Utils.pointers[1], 0, null, Utils.pointers[0]); |
||||||
|
long event = Utils.pointers[0].get(0); |
||||||
|
return new JoclEvent(event); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void acquireImageForSharingNoEvent(CommandQueue queue) { |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[1].put(0, id); |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
((CLGL) cl).clEnqueueAcquireGLObjects(q, 1, Utils.pointers[1], 0, null, null); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public Event releaseImageForSharingAsync(CommandQueue queue) { |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[1].put(0, id); |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
((CLGL) cl).clEnqueueReleaseGLObjects(q, 1, Utils.pointers[1], 0, null, Utils.pointers[0]); |
||||||
|
long event = Utils.pointers[0].get(0); |
||||||
|
return new JoclEvent(event); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void releaseImageForSharingNoEvent(CommandQueue queue) { |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[1].put(0, id); |
||||||
|
long q = ((JoclCommandQueue)queue).id; |
||||||
|
((CLGL) cl).clEnqueueReleaseGLObjects(q, 1, Utils.pointers[1], 0, null, null); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private long mem; |
||||||
|
private ReleaserImpl(long mem) { |
||||||
|
this.mem = mem; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (mem != 0) { |
||||||
|
int ret = CLPlatform.getLowLevelCLInterface().clReleaseMemObject(mem); |
||||||
|
mem = 0; |
||||||
|
Utils.reportError(ret, "clReleaseMemObject"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,290 @@ |
|||||||
|
/* |
||||||
|
* 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.jocl; |
||||||
|
|
||||||
|
import com.jme3.math.Matrix4f; |
||||||
|
import com.jme3.math.Quaternion; |
||||||
|
import com.jme3.math.Vector2f; |
||||||
|
import com.jme3.math.Vector4f; |
||||||
|
import com.jme3.opencl.*; |
||||||
|
import com.jme3.opencl.Buffer; |
||||||
|
import com.jogamp.common.nio.PointerBuffer; |
||||||
|
import com.jogamp.opencl.CLPlatform; |
||||||
|
import com.jogamp.opencl.llb.CL; |
||||||
|
import java.nio.*; |
||||||
|
import java.nio.charset.Charset; |
||||||
|
|
||||||
|
import static com.jogamp.common.os.Platform.is32Bit; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class JoclKernel extends Kernel { |
||||||
|
|
||||||
|
final long kernel; |
||||||
|
final CL cl; |
||||||
|
|
||||||
|
public JoclKernel(long kernel) { |
||||||
|
super(new ReleaserImpl(kernel)); |
||||||
|
this.kernel = kernel; |
||||||
|
this.cl = CLPlatform.getLowLevelCLInterface(); |
||||||
|
OpenCLObjectManager.getInstance().registerObject(this); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
int ret = cl.clGetKernelInfo(kernel, CL.CL_KERNEL_FUNCTION_NAME, 0, null, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clGetKernelInfo"); |
||||||
|
int count = (int) Utils.pointers[0].get(0); |
||||||
|
ByteBuffer buf = ByteBuffer.allocateDirect(count); |
||||||
|
ret = cl.clGetKernelInfo(kernel, CL.CL_KERNEL_FUNCTION_NAME, count, buf, null); |
||||||
|
Utils.checkError(ret, "clGetKernelInfo"); |
||||||
|
byte[] data = new byte[count]; |
||||||
|
buf.get(data); |
||||||
|
return new String(data, Charset.forName("ASCII")); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getArgCount() { |
||||||
|
Utils.tempBuffers[0].b16i.rewind(); |
||||||
|
int ret = cl.clGetKernelInfo(kernel, CL.CL_KERNEL_NUM_ARGS, 4, Utils.tempBuffers[0].b16i, null); |
||||||
|
Utils.checkError(ret, "clGetKernelInfo"); |
||||||
|
return Utils.tempBuffers[0].b16i.get(0); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaxWorkGroupSize(Device device) { |
||||||
|
long d = ((JoclDevice) device).id; |
||||||
|
Utils.tempBuffers[0].b16l.rewind(); |
||||||
|
int ret = cl.clGetKernelWorkGroupInfo(kernel, d, CL.CL_KERNEL_WORK_GROUP_SIZE, 8, Utils.tempBuffers[0].b16l, null); |
||||||
|
Utils.checkError(ret, "clGetKernelWorkGroupInfo"); |
||||||
|
return Utils.tempBuffers[0].b16l.get(0); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, LocalMemPerElement t) { |
||||||
|
int ret = cl.clSetKernelArg (kernel, index, t.getSize() * workGroupSize.getSizes()[0] * workGroupSize.getSizes()[1] * workGroupSize.getSizes()[2], null); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, LocalMem t) { |
||||||
|
int ret = cl.clSetKernelArg (kernel, index, t.getSize(), null); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Buffer t) { |
||||||
|
Utils.tempBuffers[0].b16l.rewind(); |
||||||
|
Utils.tempBuffers[0].b16l.put(0, ((JoclBuffer) t).id); |
||||||
|
int ret = cl.clSetKernelArg(kernel, index, is32Bit()?4:8, Utils.tempBuffers[0].b16l); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Image i) { |
||||||
|
Utils.tempBuffers[0].b16l.rewind(); |
||||||
|
Utils.tempBuffers[0].b16l.put(0, ((JoclImage) i).id); |
||||||
|
int ret = cl.clSetKernelArg(kernel, index, is32Bit()?4:8, Utils.tempBuffers[0].b16l); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, byte b) { |
||||||
|
ByteBuffer buf = Utils.tempBuffers[0].b16; |
||||||
|
buf.position(0); |
||||||
|
buf.put(0, b); |
||||||
|
int ret = cl.clSetKernelArg(kernel, index, 1, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, short s) { |
||||||
|
ShortBuffer buf = Utils.tempBuffers[0].b16s; |
||||||
|
buf.position(0); |
||||||
|
buf.put(0, s); |
||||||
|
int ret = cl.clSetKernelArg(kernel, index, 2, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, int i) { |
||||||
|
IntBuffer buf = Utils.tempBuffers[0].b16i; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(1); |
||||||
|
buf.put(0, i); |
||||||
|
int ret = cl.clSetKernelArg(kernel, index, 4, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, long l) { |
||||||
|
LongBuffer buf = Utils.tempBuffers[0].b16l; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(1); |
||||||
|
buf.put(0, l); |
||||||
|
int ret = cl.clSetKernelArg(kernel, index, 8, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, float f) { |
||||||
|
FloatBuffer buf = Utils.tempBuffers[0].b16f; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(1); |
||||||
|
buf.put(0, f); |
||||||
|
int ret = cl.clSetKernelArg(kernel, index, 4, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, double d) { |
||||||
|
DoubleBuffer buf = Utils.tempBuffers[0].b16d; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(1); |
||||||
|
buf.put(0, d); |
||||||
|
int ret = cl.clSetKernelArg(kernel, index, 8, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Vector2f v) { |
||||||
|
FloatBuffer buf = Utils.tempBuffers[0].b16f; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(2); |
||||||
|
buf.put(0, v.x); |
||||||
|
buf.put(1, v.y); |
||||||
|
int ret = cl.clSetKernelArg(kernel, index, 8, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Vector4f v) { |
||||||
|
FloatBuffer buf = Utils.tempBuffers[0].b16f; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(4); |
||||||
|
buf.put(0, v.x); |
||||||
|
buf.put(1, v.y); |
||||||
|
buf.put(2, v.z); |
||||||
|
buf.put(3, v.w); |
||||||
|
int ret = cl.clSetKernelArg(kernel, index, 16, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Quaternion q) { |
||||||
|
FloatBuffer buf = Utils.tempBuffers[0].b16f; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(4); |
||||||
|
buf.put(0, q.getX()); |
||||||
|
buf.put(1, q.getY()); |
||||||
|
buf.put(2, q.getZ()); |
||||||
|
buf.put(3, q.getW()); |
||||||
|
int ret = cl.clSetKernelArg(kernel, index, 16, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Matrix4f m) { |
||||||
|
FloatBuffer buf = Utils.b80f; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(16); |
||||||
|
buf.put(m.m00).put(m.m01).put(m.m02).put(m.m03); |
||||||
|
buf.put(m.m10).put(m.m11).put(m.m12).put(m.m13); |
||||||
|
buf.put(m.m20).put(m.m21).put(m.m22).put(m.m23); |
||||||
|
buf.put(m.m30).put(m.m31).put(m.m32).put(m.m33); |
||||||
|
buf.position(0); |
||||||
|
int ret = cl.clSetKernelArg(kernel, index, 16*4, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, ByteBuffer buffer, long size) { |
||||||
|
int ret = cl.clSetKernelArg(kernel, index, size, buffer); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event Run(CommandQueue queue) { |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[1].put(globalWorkSize.getSizes(), 0, globalWorkSize.getSizes().length); |
||||||
|
Utils.pointers[1].position(0); |
||||||
|
PointerBuffer p2 = null; |
||||||
|
if (workGroupSize.getSizes()[0] > 0) { |
||||||
|
p2 = Utils.pointers[2].rewind(); |
||||||
|
p2.put(workGroupSize.getSizes(), 0, workGroupSize.getSizes().length); |
||||||
|
p2.position(0); |
||||||
|
} |
||||||
|
long q = ((JoclCommandQueue) queue).id; |
||||||
|
int ret = cl.clEnqueueNDRangeKernel(q, kernel, |
||||||
|
globalWorkSize.getDimension(), null, Utils.pointers[1], |
||||||
|
p2, 0, null, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueNDRangeKernel"); |
||||||
|
return new JoclEvent(Utils.pointers[0].get(0)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void RunNoEvent(CommandQueue queue) { |
||||||
|
Utils.pointers[1].rewind(); |
||||||
|
Utils.pointers[1].put(globalWorkSize.getSizes(), 0, globalWorkSize.getSizes().length); |
||||||
|
Utils.pointers[1].position(0); |
||||||
|
PointerBuffer p2 = null; |
||||||
|
if (workGroupSize.getSizes()[0] > 0) { |
||||||
|
p2 = Utils.pointers[2].rewind(); |
||||||
|
p2.put(workGroupSize.getSizes(), 0, workGroupSize.getSizes().length); |
||||||
|
p2.position(0); |
||||||
|
} |
||||||
|
long q = ((JoclCommandQueue) queue).id; |
||||||
|
int ret = cl.clEnqueueNDRangeKernel(q, kernel, |
||||||
|
globalWorkSize.getDimension(), null, Utils.pointers[1], |
||||||
|
p2, 0, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueNDRangeKernel"); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private long kernel; |
||||||
|
private ReleaserImpl(long kernel) { |
||||||
|
this.kernel = kernel; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (kernel != 0) { |
||||||
|
int ret = CLPlatform.getLowLevelCLInterface().clReleaseKernel(kernel); |
||||||
|
kernel = 0; |
||||||
|
Utils.reportError(ret, "clReleaseKernel"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,127 @@ |
|||||||
|
/* |
||||||
|
* 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.jocl; |
||||||
|
|
||||||
|
import com.jme3.opencl.Device; |
||||||
|
import com.jme3.opencl.Platform; |
||||||
|
import com.jogamp.opencl.CLDevice; |
||||||
|
import com.jogamp.opencl.CLPlatform; |
||||||
|
import com.jogamp.opencl.llb.CL; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public final class JoclPlatform implements Platform { |
||||||
|
|
||||||
|
final CLPlatform platform; |
||||||
|
List<JoclDevice> devices; |
||||||
|
|
||||||
|
public JoclPlatform(CLPlatform platform) { |
||||||
|
this.platform = platform; |
||||||
|
} |
||||||
|
|
||||||
|
public CLPlatform getPlatform() { |
||||||
|
return platform; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<JoclDevice> getDevices() { |
||||||
|
if (devices == null) { |
||||||
|
devices = new ArrayList<>(); |
||||||
|
for (CLDevice d : platform.listCLDevices()) { |
||||||
|
devices.add(new JoclDevice(d, this)); |
||||||
|
} |
||||||
|
} |
||||||
|
return devices; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getProfile() { |
||||||
|
return platform.getProfile(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isFullProfile() { |
||||||
|
return getProfile().contains("FULL_PROFILE"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isEmbeddedProfile() { |
||||||
|
return getProfile().contains("EMBEDDED_PROFILE"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getVersion() { |
||||||
|
return platform.getVendor(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getVersionMajor() { |
||||||
|
return Utils.getMajorVersion(getVersion(), "OpenCL "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getVersionMinor() { |
||||||
|
return Utils.getMinorVersion(getVersion(), "OpenCL "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return platform.getName(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getVendor() { |
||||||
|
return platform.getVendor(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasExtension(String extension) { |
||||||
|
return getExtensions().contains(extension); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasOpenGLInterop() { |
||||||
|
return hasExtension("cl_khr_gl_sharing"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Collection<? extends String> getExtensions() { |
||||||
|
return platform.getExtensions(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,194 @@ |
|||||||
|
/* |
||||||
|
* 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.jocl; |
||||||
|
|
||||||
|
import com.jme3.opencl.*; |
||||||
|
import com.jogamp.common.nio.Buffers; |
||||||
|
import com.jogamp.common.nio.PointerBuffer; |
||||||
|
import com.jogamp.opencl.CLPlatform; |
||||||
|
import com.jogamp.opencl.CLProgram; |
||||||
|
import com.jogamp.opencl.llb.CL; |
||||||
|
import com.jogamp.opencl.util.CLUtil; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
import static com.jogamp.common.nio.Buffers.newDirectByteBuffer; |
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class JoclProgram extends Program { |
||||||
|
private static final Logger LOG = Logger.getLogger(JoclProgram.class.getName()); |
||||||
|
|
||||||
|
final long program; |
||||||
|
final CL cl; |
||||||
|
private final JoclContext context; |
||||||
|
|
||||||
|
public JoclProgram(long program, JoclContext context) { |
||||||
|
super(new ReleaserImpl(program)); |
||||||
|
this.program = program; |
||||||
|
this.context = context; |
||||||
|
this.cl = CLPlatform.getLowLevelCLInterface(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void build(String args, Device... devices) throws KernelCompilationException { |
||||||
|
PointerBuffer deviceList = null; |
||||||
|
int deviceCount = 0; |
||||||
|
if (devices != null) { |
||||||
|
deviceList = PointerBuffer.allocateDirect(devices.length); |
||||||
|
for (Device d : devices) { |
||||||
|
deviceList.put(((JoclDevice) d).id); |
||||||
|
} |
||||||
|
deviceCount = devices.length; |
||||||
|
deviceList.rewind(); |
||||||
|
} |
||||||
|
int ret = cl.clBuildProgram(program, deviceCount, deviceList, args, null); |
||||||
|
if (ret != CL.CL_SUCCESS) { |
||||||
|
String log = Log(); |
||||||
|
LOG.log(Level.WARNING, "Unable to compile program:\n{0}", log); |
||||||
|
if (ret == CL.CL_BUILD_PROGRAM_FAILURE) { |
||||||
|
throw new KernelCompilationException("Failed to build program", ret, log); |
||||||
|
} else { |
||||||
|
Utils.checkError(ret, "clBuildProgram"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
LOG.log(Level.INFO, "Program compiled:\n{0}", Log()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private String Log(long device) { |
||||||
|
Utils.pointers[0].rewind(); |
||||||
|
int ret = cl.clGetProgramBuildInfo(program, device, CL.CL_PROGRAM_BUILD_LOG, 0, null, Utils.pointers[0]); |
||||||
|
Utils.checkError(ret, "clGetProgramBuildInfo"); |
||||||
|
int count = (int) Utils.pointers[0].get(0); |
||||||
|
final ByteBuffer buffer = newDirectByteBuffer(count); |
||||||
|
ret = cl.clGetProgramBuildInfo(program, device, CL.CL_PROGRAM_BUILD_LOG, buffer.capacity(), buffer, null); |
||||||
|
Utils.checkError(ret, "clGetProgramBuildInfo"); |
||||||
|
return CLUtil.clString2JavaString(buffer, count); |
||||||
|
} |
||||||
|
|
||||||
|
private String Log() { |
||||||
|
StringBuilder str = new StringBuilder(); |
||||||
|
for (JoclDevice device : context.getDevices()) { |
||||||
|
long d = device.id; |
||||||
|
str.append(device.getName()).append(":\n"); |
||||||
|
str.append(Log(d)); |
||||||
|
str.append('\n'); |
||||||
|
} |
||||||
|
return str.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Kernel createKernel(String name) { |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
long kernel = cl.clCreateKernel(program, name, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateKernel"); |
||||||
|
return new JoclKernel(kernel); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Kernel[] createAllKernels() { |
||||||
|
Utils.tempBuffers[0].b16i.rewind(); |
||||||
|
int ret = cl.clCreateKernelsInProgram(program, 0, null, Utils.tempBuffers[0].b16i); |
||||||
|
Utils.checkError(ret, "clCreateKernelsInProgram"); |
||||||
|
int count = Utils.tempBuffers[0].b16i.get(0); |
||||||
|
PointerBuffer buf = PointerBuffer.allocateDirect(count); |
||||||
|
ret = cl.clCreateKernelsInProgram(program, count, buf, null); |
||||||
|
Utils.checkError(ret, "clCreateKernelsInProgram"); |
||||||
|
Kernel[] kx = new Kernel[count]; |
||||||
|
for (int i=0; i<count; ++i) { |
||||||
|
kx[i] = new JoclKernel(buf.get()); |
||||||
|
} |
||||||
|
return kx; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ByteBuffer getBinary(Device d) { |
||||||
|
|
||||||
|
JoclDevice device = (JoclDevice) d; |
||||||
|
|
||||||
|
Utils.tempBuffers[0].b16i.rewind(); |
||||||
|
int ret = cl.clGetProgramInfo(program, CL.CL_PROGRAM_NUM_DEVICES, 4, Utils.tempBuffers[0].b16i, null); |
||||||
|
Utils.checkError(ret, "clGetProgramInfo: CL_PROGRAM_NUM_DEVICES"); |
||||||
|
int numDevices = Utils.tempBuffers[0].b16i.get(0); |
||||||
|
|
||||||
|
PointerBuffer devices = PointerBuffer.allocateDirect(numDevices); |
||||||
|
ret = cl.clGetProgramInfo(program, CL.CL_PROGRAM_DEVICES, numDevices * PointerBuffer.ELEMENT_SIZE, devices.getBuffer(), null); |
||||||
|
Utils.checkError(ret, "clGetProgramInfo: CL_PROGRAM_DEVICES"); |
||||||
|
int index = -1; |
||||||
|
for (int i=0; i<numDevices; ++i) { |
||||||
|
if (devices.get(i) == device.id) { |
||||||
|
index = i; |
||||||
|
} |
||||||
|
} |
||||||
|
if (index == -1) { |
||||||
|
throw new com.jme3.opencl.OpenCLException("Program was not built against the specified device "+device); |
||||||
|
} |
||||||
|
|
||||||
|
final PointerBuffer sizes = PointerBuffer.allocateDirect(numDevices); |
||||||
|
ret = cl.clGetProgramInfo(program, CL.CL_PROGRAM_BINARY_SIZES, numDevices * PointerBuffer.ELEMENT_SIZE, sizes.getBuffer(), null); |
||||||
|
Utils.checkError(ret, "clGetProgramInfo: CL_PROGRAM_BINARY_SIZES"); |
||||||
|
|
||||||
|
final ByteBuffer binaries = Buffers.newDirectByteBuffer((int) sizes.get(index)); |
||||||
|
final PointerBuffer addresses = PointerBuffer.allocateDirect(numDevices); |
||||||
|
for (int i=0; i<numDevices; ++i) { |
||||||
|
if (index == i) { |
||||||
|
addresses.referenceBuffer(binaries); |
||||||
|
} else { |
||||||
|
addresses.put(0); |
||||||
|
} |
||||||
|
} |
||||||
|
addresses.rewind(); |
||||||
|
|
||||||
|
ret = cl.clGetProgramInfo(program, CL.CL_PROGRAM_BINARIES, numDevices * PointerBuffer.ELEMENT_SIZE, addresses.getBuffer(), null); |
||||||
|
Utils.checkError(ret, "clGetProgramInfo: CL_PROGRAM_BINARIES"); |
||||||
|
|
||||||
|
return binaries; |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private long program; |
||||||
|
private ReleaserImpl(long program) { |
||||||
|
this.program = program; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (program != 0) { |
||||||
|
int ret = CLPlatform.getLowLevelCLInterface().clReleaseProgram(program); |
||||||
|
program = 0; |
||||||
|
Utils.reportError(ret, "clReleaseProgram"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,162 @@ |
|||||||
|
/* |
||||||
|
* 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.jocl; |
||||||
|
|
||||||
|
import com.jme3.opencl.MappingAccess; |
||||||
|
import com.jme3.opencl.MemoryAccess; |
||||||
|
import com.jme3.opencl.OpenCLException; |
||||||
|
import com.jme3.util.BufferUtils; |
||||||
|
import com.jogamp.common.nio.PointerBuffer; |
||||||
|
import com.jogamp.opencl.CLEventList; |
||||||
|
import com.jogamp.opencl.CLException; |
||||||
|
import com.jogamp.opencl.CLMemory; |
||||||
|
import com.jogamp.opencl.CLVersion; |
||||||
|
import com.jogamp.opencl.llb.CL; |
||||||
|
import java.lang.reflect.Field; |
||||||
|
import java.nio.*; |
||||||
|
import java.util.EnumSet; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class Utils { |
||||||
|
private static final Logger LOG = Logger.getLogger(Utils.class.getName()); |
||||||
|
private Utils() {} |
||||||
|
|
||||||
|
public static int getMajorVersion(String version, String prefix) { |
||||||
|
String s = version.substring(prefix.length()); |
||||||
|
return Integer.parseInt(s); |
||||||
|
} |
||||||
|
|
||||||
|
public static int getMinorVersion(String version, String prefix) { |
||||||
|
String s = version.substring(prefix.length()); |
||||||
|
int major = Integer.parseInt(s); |
||||||
|
s = s.substring((int) (Math.log10(major) + 2)); |
||||||
|
return Integer.parseInt(s); |
||||||
|
} |
||||||
|
|
||||||
|
public static final class TempBuffer { |
||||||
|
public final ByteBuffer b16; |
||||||
|
public final ShortBuffer b16s; |
||||||
|
public final IntBuffer b16i; |
||||||
|
public final LongBuffer b16l; |
||||||
|
public final FloatBuffer b16f; |
||||||
|
public final DoubleBuffer b16d; |
||||||
|
public TempBuffer() { |
||||||
|
b16 = BufferUtils.createByteBuffer(16); |
||||||
|
b16s = b16.asShortBuffer(); |
||||||
|
b16i = b16.asIntBuffer(); |
||||||
|
b16l = b16.asLongBuffer(); |
||||||
|
b16f = b16.asFloatBuffer(); |
||||||
|
b16d = b16.asDoubleBuffer(); |
||||||
|
} |
||||||
|
} |
||||||
|
public static final ByteBuffer b80; //needed for ImageDescriptor
|
||||||
|
public static final LongBuffer b80l; |
||||||
|
public static final FloatBuffer b80f; |
||||||
|
public static final TempBuffer[] tempBuffers = new TempBuffer[8]; |
||||||
|
public static final PointerBuffer[] pointers = new PointerBuffer[8]; |
||||||
|
static { |
||||||
|
for (int i=0; i<8; ++i) { |
||||||
|
tempBuffers[i] = new TempBuffer(); |
||||||
|
pointers[i] = PointerBuffer.allocateDirect(4); |
||||||
|
} |
||||||
|
errorBuffer = BufferUtils.createIntBuffer(1); |
||||||
|
b80 = BufferUtils.createByteBuffer(80); |
||||||
|
b80l = b80.asLongBuffer(); |
||||||
|
b80f = b80.asFloatBuffer(); |
||||||
|
} |
||||||
|
|
||||||
|
public static IntBuffer errorBuffer; |
||||||
|
public static void checkError(IntBuffer errorBuffer, String callName) { |
||||||
|
checkError(errorBuffer.get(0), callName); |
||||||
|
} |
||||||
|
public static void checkError(int error, String callName) { |
||||||
|
if (error != CL.CL_SUCCESS) { |
||||||
|
String errname = getErrorName(error); |
||||||
|
if (errname == null) { |
||||||
|
errname = "UNKNOWN"; |
||||||
|
} |
||||||
|
throw new OpenCLException("OpenCL error in " + callName + ": " + errname + " (0x" + Integer.toHexString(error) + ")", error); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void reportError(int error, String callName) { |
||||||
|
if (error != CL.CL_SUCCESS) { |
||||||
|
String errname = getErrorName(error); |
||||||
|
if (errname == null) { |
||||||
|
errname = "UNKNOWN"; |
||||||
|
} |
||||||
|
LOG.log(Level.WARNING, "OpenCL error in {0}: {1} (0x{2})", new Object[]{callName, errname, Integer.toHexString(error)}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static String getErrorName(int code) { |
||||||
|
return CLException.resolveErrorCode(code); |
||||||
|
} |
||||||
|
|
||||||
|
public static long getMemoryAccessFlags(MemoryAccess ma) { |
||||||
|
switch (ma) { |
||||||
|
case READ_ONLY: return CL.CL_MEM_READ_ONLY; |
||||||
|
case WRITE_ONLY: return CL.CL_MEM_WRITE_ONLY; |
||||||
|
case READ_WRITE: return CL.CL_MEM_READ_WRITE; |
||||||
|
default: throw new IllegalArgumentException("Unknown memory access: "+ma); |
||||||
|
} |
||||||
|
} |
||||||
|
public static MemoryAccess getMemoryAccessFromFlag(long flag) { |
||||||
|
if ((flag & CL.CL_MEM_READ_WRITE) > 0) { |
||||||
|
return MemoryAccess.READ_WRITE; |
||||||
|
} |
||||||
|
if ((flag & CL.CL_MEM_READ_ONLY) > 0) { |
||||||
|
return MemoryAccess.READ_ONLY; |
||||||
|
} |
||||||
|
if ((flag & CL.CL_MEM_WRITE_ONLY) > 0) { |
||||||
|
return MemoryAccess.WRITE_ONLY; |
||||||
|
} |
||||||
|
throw new OpenCLException("Unknown memory access flag: "+flag); |
||||||
|
} |
||||||
|
|
||||||
|
public static long getMappingAccessFlags(MappingAccess ma) { |
||||||
|
switch (ma) { |
||||||
|
case MAP_READ_ONLY: return CL.CL_MAP_READ; |
||||||
|
case MAP_READ_WRITE: return CL.CL_MAP_READ | CL.CL_MAP_WRITE; |
||||||
|
case MAP_WRITE_ONLY: return CL.CL_MAP_WRITE; |
||||||
|
case MAP_WRITE_INVALIDATE: return CL.CL_MAP_WRITE; //MAP_WRITE_INVALIDATE_REGION not supported
|
||||||
|
default: throw new IllegalArgumentException("Unknown mapping access: "+ma); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,236 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.*; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import org.lwjgl.opencl.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class LwjglBuffer extends Buffer { |
||||||
|
|
||||||
|
private final CLMem buffer; |
||||||
|
|
||||||
|
public LwjglBuffer(CLMem buffer) { |
||||||
|
super(new ReleaserImpl(buffer)); |
||||||
|
this.buffer = buffer; |
||||||
|
} |
||||||
|
public CLMem getBuffer() { |
||||||
|
return buffer; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getSize() { |
||||||
|
return buffer.getInfoSize(CL10.CL_MEM_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public MemoryAccess getMemoryAccessFlags() { |
||||||
|
return Utils.getMemoryAccessFromFlag(buffer.getInfoLong(CL10.CL_MEM_FLAGS)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void read(CommandQueue queue, ByteBuffer dest, long size, long offset) { |
||||||
|
//Note: LWJGL does not support the size parameter, I have to set the buffer limit
|
||||||
|
dest.limit((int) (dest.position() + size)); |
||||||
|
int ret = CL10.clEnqueueReadBuffer(((LwjglCommandQueue)queue).getQueue(), |
||||||
|
buffer, CL10.CL_TRUE, offset, dest, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueReadBuffer"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event readAsync(CommandQueue queue, ByteBuffer dest, long size, long offset) { |
||||||
|
//Note: LWJGL does not support the size parameter, I have to set the buffer limit
|
||||||
|
dest.limit((int) (dest.position() + size)); |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue)queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueReadBuffer(q, buffer, CL10.CL_FALSE, offset, dest, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueReadBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(q.getCLEvent(event)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void write(CommandQueue queue, ByteBuffer src, long size, long offset) { |
||||||
|
//Note: LWJGL does not support the size parameter, I have to set the buffer limit
|
||||||
|
src.limit((int) (src.position() + size)); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue)queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueWriteBuffer(q, buffer, CL10.CL_TRUE, offset, src, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueWriteBuffer"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event writeAsync(CommandQueue queue, ByteBuffer src, long size, long offset) { |
||||||
|
//Note: LWJGL does not support the size parameter, I have to set the buffer limit
|
||||||
|
src.limit((int) (src.position() + size)); |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue)queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueWriteBuffer(q, buffer, CL10.CL_FALSE, offset, src, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueWriteBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(q.getCLEvent(event)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void copyTo(CommandQueue queue, Buffer dest, long size, long srcOffset, long destOffset) { |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue)queue).getQueue(); |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
int ret = CL10.clEnqueueCopyBuffer(q, buffer, ((LwjglBuffer) dest).buffer, srcOffset, destOffset, size, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
ret = CL10.clWaitForEvents(q.getCLEvent(event)); |
||||||
|
Utils.checkError(ret, "clWaitForEvents"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event copyToAsync(CommandQueue queue, Buffer dest, long size, long srcOffset, long destOffset) { |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue)queue).getQueue(); |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
int ret = CL10.clEnqueueCopyBuffer(q, buffer, ((LwjglBuffer) dest).buffer, srcOffset, destOffset, size, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(q.getCLEvent(event)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ByteBuffer map(CommandQueue queue, long size, long offset, MappingAccess access) { |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
long flags = Utils.getMappingAccessFlags(access); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
ByteBuffer b = CL10.clEnqueueMapBuffer(q, buffer, CL10.CL_TRUE, flags, offset, size, null, null, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer"); |
||||||
|
return b; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void unmap(CommandQueue queue, ByteBuffer ptr) { |
||||||
|
ptr.position(0); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
int ret = CL10.clEnqueueUnmapMemObject(q, buffer, ptr, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueUnmapMemObject"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
ret = CL10.clWaitForEvents(q.getCLEvent(event)); |
||||||
|
Utils.checkError(ret, "clWaitForEvents"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public com.jme3.opencl.Buffer.AsyncMapping mapAsync(CommandQueue queue, long size, long offset, MappingAccess access) { |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
long flags = Utils.getMappingAccessFlags(access); |
||||||
|
ByteBuffer buf = CL10.clEnqueueMapBuffer(q, buffer, CL10.CL_FALSE, flags, offset, size, null, Utils.pointerBuffers[0], Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new com.jme3.opencl.Buffer.AsyncMapping(new LwjglEvent(q.getCLEvent(event)), buf); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event fillAsync(CommandQueue queue, ByteBuffer pattern, long size, long offset) { |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL12.clEnqueueFillBuffer(q, buffer, pattern, offset, size, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueFillBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(q.getCLEvent(event)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event copyToImageAsync(CommandQueue queue, Image dest, long srcOffset, long[] destOrigin, long[] destRegion) { |
||||||
|
if (destOrigin.length!=3 || destRegion.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(destOrigin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(destRegion).position(0); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueCopyBufferToImage(q, buffer, ((LwjglImage) dest).getImage(), |
||||||
|
srcOffset, Utils.pointerBuffers[1], Utils.pointerBuffers[2], null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyBufferToImage"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(q.getCLEvent(event)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event acquireBufferForSharingAsync(CommandQueue queue) { |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueAcquireGLObjects(q, buffer, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueAcquireGLObjects"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(q.getCLEvent(event)); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void acquireBufferForSharingNoEvent(CommandQueue queue) { |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueAcquireGLObjects(q, buffer, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueAcquireGLObjects"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event releaseBufferForSharingAsync(CommandQueue queue) { |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueReleaseGLObjects(q, buffer, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueReleaseGLObjects"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(q.getCLEvent(event)); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void releaseBufferForSharingNoEvent(CommandQueue queue) { |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueReleaseGLObjects(q, buffer, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueReleaseGLObjects"); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private CLMem mem; |
||||||
|
private ReleaserImpl(CLMem mem) { |
||||||
|
this.mem = mem; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (mem != null) { |
||||||
|
int ret = CL10.clReleaseMemObject(mem); |
||||||
|
mem = null; |
||||||
|
Utils.reportError(ret, "clReleaseMemObject"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,82 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.CommandQueue; |
||||||
|
import com.jme3.opencl.OpenCLObjectManager; |
||||||
|
import org.lwjgl.opencl.CL10; |
||||||
|
import org.lwjgl.opencl.CLCommandQueue; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class LwjglCommandQueue extends CommandQueue { |
||||||
|
|
||||||
|
private final CLCommandQueue queue; |
||||||
|
|
||||||
|
public LwjglCommandQueue(CLCommandQueue queue) { |
||||||
|
super(new ReleaserImpl(queue)); |
||||||
|
this.queue = queue; |
||||||
|
} |
||||||
|
|
||||||
|
public CLCommandQueue getQueue() { |
||||||
|
return queue; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void flush() { |
||||||
|
int ret = CL10.clFlush(queue); |
||||||
|
Utils.checkError(ret, "clFlush"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void finish() { |
||||||
|
int ret = CL10.clFinish(queue); |
||||||
|
Utils.checkError(ret, "clFinish"); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private CLCommandQueue queue; |
||||||
|
private ReleaserImpl(CLCommandQueue queue) { |
||||||
|
this.queue = queue; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (queue != null) { |
||||||
|
int ret = CL10.clReleaseCommandQueue(queue); |
||||||
|
queue = null; |
||||||
|
Utils.reportError(ret, "clReleaseCommandQueue"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,240 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.*; |
||||||
|
import com.jme3.opencl.Context; |
||||||
|
import com.jme3.opencl.Image.ImageDescriptor; |
||||||
|
import com.jme3.opencl.Image.ImageFormat; |
||||||
|
import com.jme3.scene.VertexBuffer; |
||||||
|
import com.jme3.texture.FrameBuffer; |
||||||
|
import com.jme3.texture.Texture; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.nio.IntBuffer; |
||||||
|
import java.util.List; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import org.lwjgl.BufferUtils; |
||||||
|
import org.lwjgl.opencl.*; |
||||||
|
import org.lwjgl.opengl.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class LwjglContext extends Context { |
||||||
|
private static final Logger LOG = Logger.getLogger(LwjglContext.class.getName()); |
||||||
|
private final CLContext context; |
||||||
|
private final List<LwjglDevice> devices; |
||||||
|
|
||||||
|
public LwjglContext(CLContext context, List<LwjglDevice> devices) { |
||||||
|
super(new ReleaserImpl(context, devices)); |
||||||
|
this.context = context; |
||||||
|
this.devices = devices; |
||||||
|
} |
||||||
|
|
||||||
|
public CLContext getContext() { |
||||||
|
return context; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<LwjglDevice> getDevices() { |
||||||
|
return devices; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
@SuppressWarnings("element-type-mismatch") |
||||||
|
public CommandQueue createQueue(Device device) { |
||||||
|
assert (devices.contains(device)); //this also ensures that device is a LwjglDevice
|
||||||
|
CLDevice d = ((LwjglDevice) device).getDevice(); |
||||||
|
long properties = 0; |
||||||
|
CLCommandQueue q = CL10.clCreateCommandQueue(context, d, properties, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateCommandQueue"); |
||||||
|
return new LwjglCommandQueue(q); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Buffer createBuffer(long size, MemoryAccess access) { |
||||||
|
long flags = Utils.getMemoryAccessFlags(access); |
||||||
|
CLMem mem = CL10.clCreateBuffer(context, flags, size, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateBuffer"); |
||||||
|
return new LwjglBuffer(mem); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Buffer createBufferFromHost(ByteBuffer data, MemoryAccess access) { |
||||||
|
long flags = Utils.getMemoryAccessFlags(access); |
||||||
|
flags |= CL10.CL_MEM_USE_HOST_PTR; |
||||||
|
CLMem mem = CL10.clCreateBuffer(context, flags, data, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateBuffer"); |
||||||
|
return new LwjglBuffer(mem); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Image createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr) { |
||||||
|
long memFlags = Utils.getMemoryAccessFlags(access); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
//fill image format
|
||||||
|
Utils.tempBuffers[0].b16i.rewind(); |
||||||
|
Utils.tempBuffers[0].b16i.put(LwjglImage.decodeImageChannelOrder(format.channelOrder)) |
||||||
|
.put(LwjglImage.decodeImageChannelType(format.channelType)); |
||||||
|
Utils.tempBuffers[0].b16.rewind(); |
||||||
|
//fill image desc
|
||||||
|
Utils.b80l.rewind(); |
||||||
|
Utils.b80l.put(LwjglImage.decodeImageType(descr.type)) |
||||||
|
.put(descr.width).put(descr.height).put(descr.depth) |
||||||
|
.put(descr.arraySize).put(descr.rowPitch).put(descr.slicePitch) |
||||||
|
.put(0).put(0).put(0); |
||||||
|
Utils.b80.rewind(); |
||||||
|
//create image
|
||||||
|
CLMem mem = CL12.clCreateImage(context, memFlags, Utils.tempBuffers[0].b16, Utils.b80, descr.hostPtr, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateImage"); |
||||||
|
return new LwjglImage(mem); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageFormat[] querySupportedFormats(MemoryAccess access, Image.ImageType type) { |
||||||
|
long memFlags = Utils.getMemoryAccessFlags(access); |
||||||
|
int typeFlag = LwjglImage.decodeImageType(type); |
||||||
|
Utils.tempBuffers[0].b16i.rewind(); |
||||||
|
//query count
|
||||||
|
int ret = CL10.clGetSupportedImageFormats(context, memFlags, typeFlag, null, Utils.tempBuffers[0].b16i); |
||||||
|
Utils.checkError(ret, "clGetSupportedImageFormats"); |
||||||
|
int count = Utils.tempBuffers[0].b16i.get(0); |
||||||
|
if (count == 0) { |
||||||
|
return new ImageFormat[0]; |
||||||
|
} |
||||||
|
//get formats
|
||||||
|
ByteBuffer formatsB = BufferUtils.createByteBuffer(count * 8); |
||||||
|
ret = CL10.clGetSupportedImageFormats(context, memFlags, typeFlag, formatsB, null); |
||||||
|
Utils.checkError(ret, "clGetSupportedImageFormats"); |
||||||
|
//convert formats
|
||||||
|
ImageFormat[] formats = new ImageFormat[count]; |
||||||
|
IntBuffer formatsBi = formatsB.asIntBuffer(); |
||||||
|
formatsBi.rewind(); |
||||||
|
for (int i=0; i<count; ++i) { |
||||||
|
Image.ImageChannelOrder channelOrder = LwjglImage.encodeImageChannelOrder(formatsBi.get()); |
||||||
|
Image.ImageChannelType channelType = LwjglImage.encodeImageChannelType(formatsBi.get()); |
||||||
|
formats[i] = new ImageFormat(channelOrder, channelType); |
||||||
|
} |
||||||
|
return formats; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Buffer bindVertexBuffer(VertexBuffer vb, MemoryAccess access) { |
||||||
|
int id = vb.getId(); |
||||||
|
if (id == -1) { |
||||||
|
throw new IllegalArgumentException("vertex buffer was not yet uploaded to the GPU or is CPU only"); |
||||||
|
} |
||||||
|
long flags = Utils.getMemoryAccessFlags(access); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
CLMem mem = CL10GL.clCreateFromGLBuffer(context, flags, id, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateFromGLBuffer"); |
||||||
|
return new LwjglBuffer(mem); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Image bindImage(com.jme3.texture.Image image, Texture.Type textureType, int miplevel, MemoryAccess access) { |
||||||
|
int imageID = image.getId(); |
||||||
|
if (imageID == -1) { |
||||||
|
throw new IllegalArgumentException("image was not yet uploaded to the GPU"); |
||||||
|
} |
||||||
|
long memFlags = Utils.getMemoryAccessFlags(access); |
||||||
|
int textureTarget = convertTextureType(textureType); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
CLMem mem = CL12GL.clCreateFromGLTexture(context, memFlags, textureTarget, miplevel, imageID, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateFromGLTexture"); |
||||||
|
return new LwjglImage(mem); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Image bindPureRenderBuffer(FrameBuffer.RenderBuffer buffer, MemoryAccess access) { |
||||||
|
int renderbuffer = buffer.getId(); |
||||||
|
if (renderbuffer == -1) { |
||||||
|
throw new IllegalArgumentException("renderbuffer was not yet uploaded to the GPU"); |
||||||
|
} |
||||||
|
long memFlags = Utils.getMemoryAccessFlags(access); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
CLMem mem = CL10GL.clCreateFromGLRenderbuffer(context, memFlags, renderbuffer, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateFromGLRenderbuffer"); |
||||||
|
return new LwjglImage(mem); |
||||||
|
} |
||||||
|
|
||||||
|
private int convertTextureType(Texture.Type textureType) { |
||||||
|
switch (textureType) { |
||||||
|
case TwoDimensional: return GL11.GL_TEXTURE_2D; |
||||||
|
case TwoDimensionalArray: return GL30.GL_TEXTURE_2D_ARRAY; |
||||||
|
case ThreeDimensional: return GL12.GL_TEXTURE_3D; |
||||||
|
case CubeMap: return GL13.GL_TEXTURE_CUBE_MAP; |
||||||
|
default: throw new IllegalArgumentException("unknown texture type "+textureType); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Program createProgramFromSourceCode(String sourceCode) { |
||||||
|
LOG.log(Level.FINE, "Create program from source:\n{0}", sourceCode); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
CLProgram p = CL10.clCreateProgramWithSource(context, sourceCode, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateProgramWithSource"); |
||||||
|
return new LwjglProgram(p, this); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Program createProgramFromBinary(ByteBuffer binaries, Device device) { |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
Utils.tempBuffers[0].b16i.rewind(); |
||||||
|
CLProgram p = CL10.clCreateProgramWithBinary(context, ((LwjglDevice) device).device, |
||||||
|
binaries, Utils.tempBuffers[0].b16i, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateProgramWithBinary"); |
||||||
|
Utils.checkError(Utils.tempBuffers[0].b16i, "clCreateProgramWithBinary"); |
||||||
|
return new LwjglProgram(p, this); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private CLContext context; |
||||||
|
private final List<LwjglDevice> devices; |
||||||
|
private ReleaserImpl(CLContext mem, List<LwjglDevice> devices) { |
||||||
|
this.context = mem; |
||||||
|
this.devices = devices; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (context != null) { |
||||||
|
int ret = CL10.clReleaseContext(context); |
||||||
|
context = null; |
||||||
|
devices.clear(); |
||||||
|
Utils.reportError(ret, "clReleaseMemObject"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,293 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.Device; |
||||||
|
import com.jme3.opencl.Platform; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Collection; |
||||||
|
import org.lwjgl.opencl.CL10; |
||||||
|
import org.lwjgl.opencl.CL11; |
||||||
|
import org.lwjgl.opencl.CLDevice; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public final class LwjglDevice implements Device { |
||||||
|
|
||||||
|
final CLDevice device; |
||||||
|
final LwjglPlatform platform; |
||||||
|
|
||||||
|
public LwjglDevice(CLDevice device, LwjglPlatform platform) { |
||||||
|
this.device = device; |
||||||
|
this.platform = platform; |
||||||
|
} |
||||||
|
|
||||||
|
public CLDevice getDevice() { |
||||||
|
return device; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public LwjglPlatform getPlatform() { |
||||||
|
return platform; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public DeviceType getDeviceType() { |
||||||
|
int type = device.getInfoInt(CL10.CL_DEVICE_TYPE); |
||||||
|
switch (type) { |
||||||
|
case CL10.CL_DEVICE_TYPE_ACCELERATOR: return DeviceType.ACCELEARTOR; |
||||||
|
case CL10.CL_DEVICE_TYPE_CPU: return DeviceType.CPU; |
||||||
|
case CL10.CL_DEVICE_TYPE_GPU: return DeviceType.GPU; |
||||||
|
default: return DeviceType.DEFAULT; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getVendorId() { |
||||||
|
return device.getInfoInt(CL10.CL_DEVICE_VENDOR_ID); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isAvailable() { |
||||||
|
return device.getInfoBoolean(CL10.CL_DEVICE_AVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasCompiler() { |
||||||
|
return device.getInfoBoolean(CL10.CL_DEVICE_COMPILER_AVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasDouble() { |
||||||
|
return hasExtension("cl_khr_fp64"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasHalfFloat() { |
||||||
|
return hasExtension("cl_khr_fp16"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasErrorCorrectingMemory() { |
||||||
|
return device.getInfoBoolean(CL10.CL_DEVICE_ERROR_CORRECTION_SUPPORT); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasUnifiedMemory() { |
||||||
|
return device.getInfoBoolean(CL11.CL_DEVICE_HOST_UNIFIED_MEMORY); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasImageSupport() { |
||||||
|
return device.getInfoBoolean(CL10.CL_DEVICE_IMAGE_SUPPORT); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasWritableImage3D() { |
||||||
|
return hasExtension("cl_khr_3d_image_writes"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasOpenGLInterop() { |
||||||
|
return hasExtension("cl_khr_gl_sharing"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasExtension(String extension) { |
||||||
|
return getExtensions().contains(extension); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Collection<? extends String> getExtensions() { |
||||||
|
return Arrays.asList(device.getInfoString(CL10.CL_DEVICE_EXTENSIONS).split(" ")); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getComputeUnits() { |
||||||
|
return device.getInfoInt(CL10.CL_DEVICE_MAX_COMPUTE_UNITS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getClockFrequency() { |
||||||
|
return device.getInfoInt(CL10.CL_DEVICE_MAX_CLOCK_FREQUENCY); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getAddressBits() { |
||||||
|
return device.getInfoInt(CL10.CL_DEVICE_ADDRESS_BITS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isLittleEndian() { |
||||||
|
return device.getInfoBoolean(CL10.CL_DEVICE_ENDIAN_LITTLE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaximumWorkItemDimensions() { |
||||||
|
return device.getInfoSize(CL10.CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long[] getMaximumWorkItemSizes() { |
||||||
|
return device.getInfoSizeArray(CL10.CL_DEVICE_MAX_WORK_ITEM_SIZES); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaxiumWorkItemsPerGroup() { |
||||||
|
return device.getInfoSize(CL10.CL_DEVICE_MAX_WORK_GROUP_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getMaximumSamplers() { |
||||||
|
return device.getInfoInt(CL10.CL_DEVICE_MAX_SAMPLERS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getMaximumReadImages() { |
||||||
|
return device.getInfoInt(CL10.CL_DEVICE_MAX_READ_IMAGE_ARGS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getMaximumWriteImages() { |
||||||
|
return device.getInfoInt(CL10.CL_DEVICE_MAX_WRITE_IMAGE_ARGS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long[] getMaximumImage2DSize() { |
||||||
|
return new long[] { |
||||||
|
device.getInfoSize(CL10.CL_DEVICE_IMAGE2D_MAX_WIDTH), |
||||||
|
device.getInfoSize(CL10.CL_DEVICE_IMAGE2D_MAX_HEIGHT) |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long[] getMaximumImage3DSize() { |
||||||
|
return new long[] { |
||||||
|
device.getInfoSize(CL10.CL_DEVICE_IMAGE3D_MAX_WIDTH), |
||||||
|
device.getInfoSize(CL10.CL_DEVICE_IMAGE3D_MAX_HEIGHT), |
||||||
|
device.getInfoSize(CL10.CL_DEVICE_IMAGE3D_MAX_DEPTH) |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaximumAllocationSize() { |
||||||
|
return device.getInfoLong(CL10.CL_DEVICE_MAX_MEM_ALLOC_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getGlobalMemorySize() { |
||||||
|
return device.getInfoLong(CL10.CL_DEVICE_GLOBAL_MEM_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getLocalMemorySize() { |
||||||
|
return device.getInfoLong(CL10.CL_DEVICE_LOCAL_MEM_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaximumConstantBufferSize() { |
||||||
|
return device.getInfoLong(CL10.CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getMaximumConstantArguments() { |
||||||
|
return device.getInfoInt(CL10.CL_DEVICE_MAX_CONSTANT_ARGS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getProfile() { |
||||||
|
return device.getInfoString(CL10.CL_DEVICE_PROFILE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getVersion() { |
||||||
|
return device.getInfoString(CL10.CL_DEVICE_VERSION); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getVersionMajor() { |
||||||
|
return Utils.getMajorVersion(getVersion(), "OpenCL "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getVersionMinor() { |
||||||
|
return Utils.getMinorVersion(getVersion(), "OpenCL "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getCompilerVersion() { |
||||||
|
return device.getInfoString(CL11.CL_DEVICE_OPENCL_C_VERSION); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getCompilerVersionMajor() { |
||||||
|
return Utils.getMajorVersion(getCompilerVersion(), "OpenCL C "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getCompilerVersionMinor() { |
||||||
|
return Utils.getMinorVersion(getCompilerVersion(), "OpenCL C "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getDriverVersion() { |
||||||
|
return device.getInfoString(CL10.CL_DRIVER_VERSION); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getDriverVersionMajor() { |
||||||
|
return Utils.getMajorVersion(getDriverVersion(), ""); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getDriverVersionMinor() { |
||||||
|
return Utils.getMinorVersion(getDriverVersion(), ""); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return device.getInfoString(CL10.CL_DEVICE_NAME); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getVendor() { |
||||||
|
return device.getInfoString(CL10.CL_DEVICE_VENDOR); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return getName(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,100 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.Event; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import org.lwjgl.opencl.CL10; |
||||||
|
import org.lwjgl.opencl.CLEvent; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class LwjglEvent extends Event { |
||||||
|
private static final Logger LOG = Logger.getLogger(LwjglEvent.class.getName()); |
||||||
|
private CLEvent event; |
||||||
|
|
||||||
|
public LwjglEvent(CLEvent event) { |
||||||
|
super(new ReleaserImpl(event)); |
||||||
|
this.event = event; |
||||||
|
} |
||||||
|
|
||||||
|
public CLEvent getEvent() { |
||||||
|
return event; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void waitForFinished() { |
||||||
|
if (event==null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
CL10.clWaitForEvents(event); |
||||||
|
release(); //short cut to save resources
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isCompleted() { |
||||||
|
if (event==null) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
int status = event.getInfoInt(CL10.CL_EVENT_COMMAND_EXECUTION_STATUS); |
||||||
|
if (status == CL10.CL_SUCCESS) { |
||||||
|
release(); //short cut to save resources
|
||||||
|
return true; |
||||||
|
} else if (status < 0) { |
||||||
|
Utils.checkError(status, "EventStatus"); |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private CLEvent event; |
||||||
|
|
||||||
|
private ReleaserImpl(CLEvent event) { |
||||||
|
this.event = event; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (event != null && event.isValid()) { |
||||||
|
int ret = CL10.clReleaseEvent(event); |
||||||
|
event = null; |
||||||
|
Utils.reportError(ret, "clReleaseEvent"); |
||||||
|
LOG.finer("Event deleted"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,575 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.math.ColorRGBA; |
||||||
|
import com.jme3.opencl.*; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import org.lwjgl.opencl.*; |
||||||
|
import org.lwjgl.opencl.api.CLImageFormat; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
public CLMem getImage() { |
||||||
|
return image; |
||||||
|
} |
||||||
|
|
||||||
|
public static int decodeImageChannelOrder(ImageChannelOrder order) { |
||||||
|
switch (order) { |
||||||
|
case A: |
||||||
|
return CL10.CL_A; |
||||||
|
case ARGB: |
||||||
|
return CL10.CL_ARGB; |
||||||
|
case BGRA: |
||||||
|
return CL10.CL_BGRA; |
||||||
|
case INTENSITY: |
||||||
|
return CL10.CL_INTENSITY; |
||||||
|
case LUMINANCE: |
||||||
|
return CL10.CL_LUMINANCE; |
||||||
|
case R: |
||||||
|
return CL10.CL_R; |
||||||
|
case RA: |
||||||
|
return CL10.CL_RA; |
||||||
|
case RG: |
||||||
|
return CL10.CL_RG; |
||||||
|
case RGB: |
||||||
|
return CL10.CL_RGB; |
||||||
|
case RGBA: |
||||||
|
return CL10.CL_RGBA; |
||||||
|
case RGBx: |
||||||
|
return CL11.CL_RGBx; |
||||||
|
case RGx: |
||||||
|
return CL11.CL_RGx; |
||||||
|
case Rx: |
||||||
|
return CL11.CL_Rx; |
||||||
|
default: |
||||||
|
throw new IllegalArgumentException("unknown image channel order: " + order); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static ImageChannelOrder encodeImageChannelOrder(int order) { |
||||||
|
switch (order) { |
||||||
|
case CL10.CL_A: |
||||||
|
return ImageChannelOrder.A; |
||||||
|
case CL10.CL_ARGB: |
||||||
|
return ImageChannelOrder.ARGB; |
||||||
|
case CL10.CL_BGRA: |
||||||
|
return ImageChannelOrder.BGRA; |
||||||
|
case CL10.CL_INTENSITY: |
||||||
|
return ImageChannelOrder.INTENSITY; |
||||||
|
case CL10.CL_LUMINANCE: |
||||||
|
return ImageChannelOrder.LUMINANCE; |
||||||
|
case CL10.CL_R: |
||||||
|
return ImageChannelOrder.R; |
||||||
|
case CL10.CL_RA: |
||||||
|
return ImageChannelOrder.RA; |
||||||
|
case CL10.CL_RG: |
||||||
|
return ImageChannelOrder.RG; |
||||||
|
case CL10.CL_RGB: |
||||||
|
return ImageChannelOrder.RGB; |
||||||
|
case CL10.CL_RGBA: |
||||||
|
return ImageChannelOrder.RGBA; |
||||||
|
case CL11.CL_RGBx: |
||||||
|
return ImageChannelOrder.RGBx; |
||||||
|
case CL11.CL_RGx: |
||||||
|
return ImageChannelOrder.RGx; |
||||||
|
case CL11.CL_Rx: |
||||||
|
return ImageChannelOrder.Rx; |
||||||
|
default: |
||||||
|
//throw new com.jme3.opencl.OpenCLException("unknown image channel order id: " + order);
|
||||||
|
LOG.log(Level.WARNING, "Unknown image channel order id: {0}", order); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static int decodeImageChannelType(ImageChannelType type) { |
||||||
|
switch (type) { |
||||||
|
case FLOAT: |
||||||
|
return CL10.CL_FLOAT; |
||||||
|
case HALF_FLOAT: |
||||||
|
return CL10.CL_HALF_FLOAT; |
||||||
|
case SIGNED_INT16: |
||||||
|
return CL10.CL_SIGNED_INT16; |
||||||
|
case SIGNED_INT32: |
||||||
|
return CL10.CL_SIGNED_INT32; |
||||||
|
case SIGNED_INT8: |
||||||
|
return CL10.CL_SIGNED_INT8; |
||||||
|
case SNORM_INT16: |
||||||
|
return CL10.CL_SNORM_INT16; |
||||||
|
case SNORM_INT8: |
||||||
|
return CL10.CL_SNORM_INT8; |
||||||
|
case UNORM_INT8: |
||||||
|
return CL10.CL_UNORM_INT8; |
||||||
|
case UNORM_INT_101010: |
||||||
|
return CL10.CL_UNORM_INT_101010; |
||||||
|
case UNORM_INT16: |
||||||
|
return CL10.CL_UNORM_INT16; |
||||||
|
case UNORM_SHORT_565: |
||||||
|
return CL10.CL_UNORM_SHORT_565; |
||||||
|
case UNORM_SHORT_555: |
||||||
|
return CL10.CL_UNORM_SHORT_555; |
||||||
|
case UNSIGNED_INT16: |
||||||
|
return CL10.CL_UNSIGNED_INT16; |
||||||
|
case UNSIGNED_INT32: |
||||||
|
return CL10.CL_UNSIGNED_INT32; |
||||||
|
case UNSIGNED_INT8: |
||||||
|
return CL10.CL_UNSIGNED_INT8; |
||||||
|
default: |
||||||
|
throw new IllegalArgumentException("Unknown image channel type: " + type); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static ImageChannelType encodeImageChannelType(int type) { |
||||||
|
switch (type) { |
||||||
|
case CL10.CL_FLOAT: |
||||||
|
return ImageChannelType.FLOAT; |
||||||
|
case CL10.CL_HALF_FLOAT: |
||||||
|
return ImageChannelType.HALF_FLOAT; |
||||||
|
case CL10.CL_SIGNED_INT16: |
||||||
|
return ImageChannelType.SIGNED_INT16; |
||||||
|
case CL10.CL_SIGNED_INT32: |
||||||
|
return ImageChannelType.SIGNED_INT32; |
||||||
|
case CL10.CL_SIGNED_INT8: |
||||||
|
return ImageChannelType.SIGNED_INT8; |
||||||
|
case CL10.CL_SNORM_INT16: |
||||||
|
return ImageChannelType.SNORM_INT16; |
||||||
|
case CL10.CL_SNORM_INT8: |
||||||
|
return ImageChannelType.SNORM_INT8; |
||||||
|
case CL10.CL_UNORM_INT8: |
||||||
|
return ImageChannelType.UNORM_INT8; |
||||||
|
case CL10.CL_UNORM_INT16: |
||||||
|
return ImageChannelType.UNORM_INT16; |
||||||
|
case CL10.CL_UNORM_INT_101010: |
||||||
|
return ImageChannelType.UNORM_INT_101010; |
||||||
|
case CL10.CL_UNORM_SHORT_555: |
||||||
|
return ImageChannelType.UNORM_SHORT_555; |
||||||
|
case CL10.CL_UNORM_SHORT_565: |
||||||
|
return ImageChannelType.UNORM_SHORT_565; |
||||||
|
case CL10.CL_UNSIGNED_INT16: |
||||||
|
return ImageChannelType.UNSIGNED_INT16; |
||||||
|
case CL10.CL_UNSIGNED_INT32: |
||||||
|
return ImageChannelType.UNSIGNED_INT32; |
||||||
|
case CL10.CL_UNSIGNED_INT8: |
||||||
|
return ImageChannelType.UNSIGNED_INT8; |
||||||
|
default: |
||||||
|
//throw new com.jme3.opencl.OpenCLException("unknown image channel type id: " + type);
|
||||||
|
LOG.log(Level.WARNING, "Unknown image channel type id: {0}", type); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static int decodeImageType(ImageType type) { |
||||||
|
switch (type) { |
||||||
|
case IMAGE_1D: |
||||||
|
return CL12.CL_MEM_OBJECT_IMAGE1D; |
||||||
|
case IMAGE_1D_ARRAY: |
||||||
|
return CL12.CL_MEM_OBJECT_IMAGE1D_ARRAY; |
||||||
|
case IMAGE_1D_BUFFER: |
||||||
|
return CL12.CL_MEM_OBJECT_IMAGE1D_BUFFER; |
||||||
|
case IMAGE_2D: |
||||||
|
return CL10.CL_MEM_OBJECT_IMAGE2D; |
||||||
|
case IMAGE_2D_ARRAY: |
||||||
|
return CL12.CL_MEM_OBJECT_IMAGE2D_ARRAY; |
||||||
|
case IMAGE_3D: |
||||||
|
return CL10.CL_MEM_OBJECT_IMAGE3D; |
||||||
|
default: |
||||||
|
throw new IllegalArgumentException("Unknown image type: " + type); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static ImageType encodeImageType(int type) { |
||||||
|
switch (type) { |
||||||
|
case CL12.CL_MEM_OBJECT_IMAGE1D: |
||||||
|
return ImageType.IMAGE_1D; |
||||||
|
case CL12.CL_MEM_OBJECT_IMAGE1D_ARRAY: |
||||||
|
return ImageType.IMAGE_1D_ARRAY; |
||||||
|
case CL12.CL_MEM_OBJECT_IMAGE1D_BUFFER: |
||||||
|
return ImageType.IMAGE_1D_BUFFER; |
||||||
|
case CL10.CL_MEM_OBJECT_IMAGE2D: |
||||||
|
return ImageType.IMAGE_2D; |
||||||
|
case CL12.CL_MEM_OBJECT_IMAGE2D_ARRAY: |
||||||
|
return ImageType.IMAGE_2D_ARRAY; |
||||||
|
case CL10.CL_MEM_OBJECT_IMAGE3D: |
||||||
|
return ImageType.IMAGE_3D; |
||||||
|
default: |
||||||
|
throw new com.jme3.opencl.OpenCLException("Unknown image type id: " + type); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getWidth() { |
||||||
|
return image.getImageInfoSize(CL10.CL_IMAGE_WIDTH); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getHeight() { |
||||||
|
return image.getImageInfoSize(CL10.CL_IMAGE_HEIGHT); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getDepth() { |
||||||
|
return image.getImageInfoSize(CL10.CL_IMAGE_DEPTH); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getRowPitch() { |
||||||
|
return image.getImageInfoSize(CL10.CL_IMAGE_ROW_PITCH); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getSlicePitch() { |
||||||
|
return image.getImageInfoSize(CL10.CL_IMAGE_SLICE_PITCH); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getArraySize() { |
||||||
|
return image.getImageInfoSize(CL12.CL_IMAGE_ARRAY_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageFormat getImageFormat() { |
||||||
|
CLImageFormat format = image.getImageFormat(); |
||||||
|
return new ImageFormat( |
||||||
|
encodeImageChannelOrder(format.getChannelOrder()), |
||||||
|
encodeImageChannelType(format.getChannelType())); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageType getImageType() { |
||||||
|
int type = image.getInfoInt(CL10.CL_MEM_TYPE); |
||||||
|
return encodeImageType(type); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getElementSize() { |
||||||
|
return (int) image.getImageInfoSize(CL10.CL_IMAGE_ELEMENT_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void readImage(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueReadImage(q, image, CL10.CL_TRUE, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], |
||||||
|
rowPitch, slicePitch, dest, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueReadImage"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event readImageAsync(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueReadImage(q, image, CL10.CL_FALSE, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], |
||||||
|
rowPitch, slicePitch, dest, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueReadImage"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(q.getCLEvent(event)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void writeImage(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueWriteImage(q, image, CL10.CL_TRUE, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], |
||||||
|
rowPitch, slicePitch, dest, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueWriteImage"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event writeImageAsync(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueWriteImage(q, image, CL10.CL_FALSE, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], |
||||||
|
rowPitch, slicePitch, dest, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueWriteImage"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(q.getCLEvent(event)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void copyTo(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region) { |
||||||
|
if (srcOrigin.length!=3 || destOrigin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[3].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(srcOrigin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(destOrigin).position(0); |
||||||
|
Utils.pointerBuffers[3].put(region).position(0); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueCopyImage(q, image, ((LwjglImage) dest).getImage(), |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], Utils.pointerBuffers[3], |
||||||
|
null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyImage"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
ret = CL10.clWaitForEvents(q.getCLEvent(event)); |
||||||
|
Utils.checkError(ret, "clWaitForEvents"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event copyToAsync(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region) { |
||||||
|
if (srcOrigin.length!=3 || destOrigin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[3].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(srcOrigin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(destOrigin).position(0); |
||||||
|
Utils.pointerBuffers[3].put(region).position(0); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueCopyImage(q, image, ((LwjglImage) dest).getImage(), |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], Utils.pointerBuffers[3], |
||||||
|
null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyImage"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(q.getCLEvent(event)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageMapping map(CommandQueue queue, long[] origin, long[] region, MappingAccess access) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[3].rewind(); |
||||||
|
Utils.pointerBuffers[4].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
long flags = Utils.getMappingAccessFlags(access); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
ByteBuffer buf = CL10.clEnqueueMapImage(q, image, CL10.CL_TRUE, flags, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], |
||||||
|
Utils.pointerBuffers[3], Utils.pointerBuffers[4], null, null, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer"); |
||||||
|
return new ImageMapping(buf, Utils.pointerBuffers[3].get(0), Utils.pointerBuffers[4].get(0)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageMapping mapAsync(CommandQueue queue, long[] origin, long[] region, MappingAccess access) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[3].rewind(); |
||||||
|
Utils.pointerBuffers[4].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
long flags = Utils.getMappingAccessFlags(access); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
ByteBuffer buf = CL10.clEnqueueMapImage(q, image, CL10.CL_FALSE, flags, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], |
||||||
|
Utils.pointerBuffers[3], Utils.pointerBuffers[4], null, Utils.pointerBuffers[0], Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new ImageMapping(buf, Utils.pointerBuffers[3].get(0), Utils.pointerBuffers[4].get(0), new LwjglEvent(q.getCLEvent(event))); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void unmap(CommandQueue queue, ImageMapping mapping) { |
||||||
|
mapping.buffer.position(0); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
int ret = CL10.clEnqueueUnmapMemObject(q, image, mapping.buffer, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueUnmapMemObject"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
ret = CL10.clWaitForEvents(q.getCLEvent(event)); |
||||||
|
Utils.checkError(ret, "clWaitForEvents"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event fillAsync(CommandQueue queue, long[] origin, long[] region, ColorRGBA color) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
Utils.tempBuffers[0].b16f.rewind(); |
||||||
|
Utils.tempBuffers[0].b16f.limit(4); |
||||||
|
Utils.tempBuffers[0].b16f.put(color.r).put(color.g).put(color.b).put(color.a); |
||||||
|
Utils.tempBuffers[0].b16.rewind(); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL12.clEnqueueFillImage(q, image, Utils.tempBuffers[0].b16, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueFillImage"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(q.getCLEvent(event)); |
||||||
|
//TODO: why does q.getCLEvent(event) return null?
|
||||||
|
//This is a bug in LWJGL: they forgot to include the line
|
||||||
|
// if ( __result == CL_SUCCESS ) command_queue.registerCLEvent(event);
|
||||||
|
// after the native call
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event fillAsync(CommandQueue queue, long[] origin, long[] region, int[] color) { |
||||||
|
if (color.length != 4) { |
||||||
|
throw new IllegalArgumentException("the passed color array must have length 4"); |
||||||
|
} |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
Utils.tempBuffers[0].b16i.rewind(); |
||||||
|
Utils.tempBuffers[0].b16i.limit(4); |
||||||
|
Utils.tempBuffers[0].b16i.put(color); |
||||||
|
Utils.tempBuffers[0].b16.rewind(); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL12.clEnqueueFillImage(q, image, Utils.tempBuffers[0].b16, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueFillImage"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(q.getCLEvent(event)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event copyToBufferAsync(CommandQueue queue, Buffer dest, long[] srcOrigin, long[] srcRegion, long destOffset) { |
||||||
|
if (srcOrigin.length!=3 || srcRegion.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(srcOrigin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(srcRegion).position(0); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueCopyImageToBuffer(q, image, ((LwjglBuffer) dest).getBuffer(), |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], destOffset, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyImageToBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(q.getCLEvent(event)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event acquireImageForSharingAsync(CommandQueue queue) { |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueAcquireGLObjects(q, image, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueAcquireGLObjects"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(q.getCLEvent(event)); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void acquireImageForSharingNoEvent(CommandQueue queue) { |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueAcquireGLObjects(q, image, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueAcquireGLObjects"); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public Event releaseImageForSharingAsync(CommandQueue queue) { |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueReleaseGLObjects(q, image, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueReleaseGLObjects"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(q.getCLEvent(event)); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void releaseImageForSharingNoEvent(CommandQueue queue) { |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueReleaseGLObjects(q, image, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueReleaseGLObjects"); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private CLMem mem; |
||||||
|
private ReleaserImpl(CLMem mem) { |
||||||
|
this.mem = mem; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (mem != null) { |
||||||
|
int ret = CL10.clReleaseMemObject(mem); |
||||||
|
mem = null; |
||||||
|
Utils.reportError(ret, "clReleaseMemObject"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,277 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.math.Matrix4f; |
||||||
|
import com.jme3.math.Quaternion; |
||||||
|
import com.jme3.math.Vector2f; |
||||||
|
import com.jme3.math.Vector4f; |
||||||
|
import com.jme3.opencl.*; |
||||||
|
import com.jme3.opencl.Buffer; |
||||||
|
import java.nio.*; |
||||||
|
import org.lwjgl.PointerBuffer; |
||||||
|
import org.lwjgl.opencl.CL10; |
||||||
|
import org.lwjgl.opencl.CLCommandQueue; |
||||||
|
import org.lwjgl.opencl.CLDevice; |
||||||
|
import org.lwjgl.opencl.CLKernel; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class LwjglKernel extends Kernel { |
||||||
|
|
||||||
|
private final CLKernel kernel; |
||||||
|
|
||||||
|
public LwjglKernel(CLKernel kernel) { |
||||||
|
super(new ReleaserImpl(kernel)); |
||||||
|
this.kernel = kernel; |
||||||
|
} |
||||||
|
|
||||||
|
public CLKernel getKernel() { |
||||||
|
return kernel; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return kernel.getInfoString(CL10.CL_KERNEL_FUNCTION_NAME); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getArgCount() { |
||||||
|
return kernel.getInfoInt(CL10.CL_KERNEL_NUM_ARGS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaxWorkGroupSize(Device device) { |
||||||
|
CLDevice d = ((LwjglDevice) device).getDevice(); |
||||||
|
return kernel.getWorkGroupInfoSize(d, CL10.CL_KERNEL_WORK_GROUP_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, LocalMemPerElement t) { |
||||||
|
int ret = CL10.clSetKernelArg (kernel, index, t.getSize() * workGroupSize.getSizes()[0] * workGroupSize.getSizes()[1] * workGroupSize.getSizes()[2]); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, LocalMem t) { |
||||||
|
int ret = CL10.clSetKernelArg (kernel, index, t.getSize()); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Buffer t) { |
||||||
|
int ret = CL10.clSetKernelArg(kernel, index, ((LwjglBuffer) t).getBuffer()); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Image i) { |
||||||
|
int ret = CL10.clSetKernelArg(kernel, index, ((LwjglImage) i).getImage()); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, byte b) { |
||||||
|
ByteBuffer buf = Utils.tempBuffers[0].b16; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(1); |
||||||
|
buf.put(0, b); |
||||||
|
int ret = CL10.clSetKernelArg(kernel, index, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, short s) { |
||||||
|
ShortBuffer buf = Utils.tempBuffers[0].b16s; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(1); |
||||||
|
buf.put(0, s); |
||||||
|
int ret = CL10.clSetKernelArg(kernel, index, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, int i) { |
||||||
|
IntBuffer buf = Utils.tempBuffers[0].b16i; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(1); |
||||||
|
buf.put(0, i); |
||||||
|
int ret = CL10.clSetKernelArg(kernel, index, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, long l) { |
||||||
|
LongBuffer buf = Utils.tempBuffers[0].b16l; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(1); |
||||||
|
buf.put(0, l); |
||||||
|
int ret = CL10.clSetKernelArg(kernel, index, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, float f) { |
||||||
|
FloatBuffer buf = Utils.tempBuffers[0].b16f; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(1); |
||||||
|
buf.put(0, f); |
||||||
|
int ret = CL10.clSetKernelArg(kernel, index, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, double d) { |
||||||
|
DoubleBuffer buf = Utils.tempBuffers[0].b16d; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(1); |
||||||
|
buf.put(0, d); |
||||||
|
int ret = CL10.clSetKernelArg(kernel, index, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Vector2f v) { |
||||||
|
FloatBuffer buf = Utils.tempBuffers[0].b16f; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(2); |
||||||
|
buf.put(0, v.x); |
||||||
|
buf.put(1, v.y); |
||||||
|
int ret = CL10.clSetKernelArg(kernel, index, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Vector4f v) { |
||||||
|
FloatBuffer buf = Utils.tempBuffers[0].b16f; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(4); |
||||||
|
buf.put(0, v.x); |
||||||
|
buf.put(1, v.y); |
||||||
|
buf.put(2, v.z); |
||||||
|
buf.put(3, v.w); |
||||||
|
int ret = CL10.clSetKernelArg(kernel, index, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Quaternion q) { |
||||||
|
FloatBuffer buf = Utils.tempBuffers[0].b16f; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(4); |
||||||
|
buf.put(0, q.getX()); |
||||||
|
buf.put(1, q.getY()); |
||||||
|
buf.put(2, q.getZ()); |
||||||
|
buf.put(3, q.getW()); |
||||||
|
int ret = CL10.clSetKernelArg(kernel, index, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Matrix4f m) { |
||||||
|
FloatBuffer buf = Utils.b80f; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(16); |
||||||
|
buf.put(m.m00).put(m.m01).put(m.m02).put(m.m03); |
||||||
|
buf.put(m.m10).put(m.m11).put(m.m12).put(m.m13); |
||||||
|
buf.put(m.m20).put(m.m21).put(m.m22).put(m.m23); |
||||||
|
buf.put(m.m30).put(m.m31).put(m.m32).put(m.m33); |
||||||
|
buf.position(0); |
||||||
|
int ret = CL10.clSetKernelArg(kernel, index, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, ByteBuffer buffer, long size) { |
||||||
|
buffer.limit((int) (buffer.position() + size)); |
||||||
|
int ret = CL10.clSetKernelArg(kernel, index, buffer); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event Run(CommandQueue queue) { |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(globalWorkSize.getSizes()); |
||||||
|
Utils.pointerBuffers[1].position(0); |
||||||
|
PointerBuffer p2 = null; |
||||||
|
if (workGroupSize.getSizes()[0] > 0) { |
||||||
|
p2 = Utils.pointerBuffers[2].rewind(); |
||||||
|
p2.put(workGroupSize.getSizes()); |
||||||
|
p2.position(0); |
||||||
|
} |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueNDRangeKernel(q, kernel, |
||||||
|
globalWorkSize.getDimension(), null, Utils.pointerBuffers[1], |
||||||
|
p2, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueNDRangeKernel"); |
||||||
|
return new LwjglEvent(q.getCLEvent(Utils.pointerBuffers[0].get(0))); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void RunNoEvent(CommandQueue queue) { |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(globalWorkSize.getSizes()); |
||||||
|
Utils.pointerBuffers[1].position(0); |
||||||
|
PointerBuffer p2 = null; |
||||||
|
if (workGroupSize.getSizes()[0] > 0) { |
||||||
|
p2 = Utils.pointerBuffers[2].rewind(); |
||||||
|
p2.put(workGroupSize.getSizes()); |
||||||
|
p2.position(0); |
||||||
|
} |
||||||
|
CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueNDRangeKernel(q, kernel, |
||||||
|
globalWorkSize.getDimension(), null, Utils.pointerBuffers[1], |
||||||
|
p2, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueNDRangeKernel"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ObjectReleaser getReleaser() { |
||||||
|
return new ReleaserImpl(kernel); |
||||||
|
} |
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private CLKernel kernel; |
||||||
|
private ReleaserImpl(CLKernel kernel) { |
||||||
|
this.kernel = kernel; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (kernel != null) { |
||||||
|
int ret = CL10.clReleaseKernel(kernel); |
||||||
|
kernel = null; |
||||||
|
Utils.reportError(ret, "clReleaseKernel"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,127 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.Device; |
||||||
|
import com.jme3.opencl.Platform; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.List; |
||||||
|
import org.lwjgl.opencl.CL10; |
||||||
|
import org.lwjgl.opencl.CLDevice; |
||||||
|
import org.lwjgl.opencl.CLPlatform; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public final class LwjglPlatform implements Platform { |
||||||
|
|
||||||
|
final CLPlatform platform; |
||||||
|
List<LwjglDevice> devices; |
||||||
|
|
||||||
|
public LwjglPlatform(CLPlatform platform) { |
||||||
|
this.platform = platform; |
||||||
|
} |
||||||
|
|
||||||
|
public CLPlatform getPlatform() { |
||||||
|
return platform; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<LwjglDevice> getDevices() { |
||||||
|
if (devices == null) { |
||||||
|
devices = new ArrayList<>(); |
||||||
|
for (CLDevice d : platform.getDevices(CL10.CL_DEVICE_TYPE_ALL)) { |
||||||
|
devices.add(new LwjglDevice(d, this)); |
||||||
|
} |
||||||
|
} |
||||||
|
return devices; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getProfile() { |
||||||
|
return platform.getInfoString(CL10.CL_PLATFORM_PROFILE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isFullProfile() { |
||||||
|
return getProfile().contains("FULL_PROFILE"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isEmbeddedProfile() { |
||||||
|
return getProfile().contains("EMBEDDED_PROFILE"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getVersion() { |
||||||
|
return platform.getInfoString(CL10.CL_PLATFORM_VERSION); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getVersionMajor() { |
||||||
|
return Utils.getMajorVersion(getVersion(), "OpenCL "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getVersionMinor() { |
||||||
|
return Utils.getMinorVersion(getVersion(), "OpenCL "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return platform.getInfoString(CL10.CL_PLATFORM_NAME); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getVendor() { |
||||||
|
return platform.getInfoString(CL10.CL_PLATFORM_VENDOR); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasExtension(String extension) { |
||||||
|
return getExtensions().contains(extension); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasOpenGLInterop() { |
||||||
|
return hasExtension("cl_khr_gl_sharing"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Collection<? extends String> getExtensions() { |
||||||
|
return Arrays.asList(platform.getInfoString(CL10.CL_PLATFORM_EXTENSIONS).split(" ")); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,145 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.*; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import org.lwjgl.PointerBuffer; |
||||||
|
import org.lwjgl.opencl.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
public CLProgram getProgram() { |
||||||
|
return program; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void build(String args, Device... devices) throws KernelCompilationException { |
||||||
|
PointerBuffer deviceList = null; |
||||||
|
if (devices != null) { |
||||||
|
deviceList = PointerBuffer.allocateDirect(devices.length); |
||||||
|
deviceList.rewind(); |
||||||
|
for (Device d : devices) { |
||||||
|
deviceList.put(((LwjglDevice) d).device.getPointer()); |
||||||
|
} |
||||||
|
deviceList.flip(); |
||||||
|
} |
||||||
|
int ret = CL10.clBuildProgram(program, deviceList, args, null); |
||||||
|
if (ret != CL10.CL_SUCCESS) { |
||||||
|
String log = Log(); |
||||||
|
LOG.log(Level.WARNING, "Unable to compile program:\n{0}", log); |
||||||
|
if (ret == CL10.CL_BUILD_PROGRAM_FAILURE) { |
||||||
|
throw new KernelCompilationException("Failed to build program", ret, log); |
||||||
|
} else { |
||||||
|
Utils.checkError(ret, "clBuildProgram"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
LOG.log(Level.INFO, "Program compiled:\n{0}", Log()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private String Log() { |
||||||
|
StringBuilder str = new StringBuilder(); |
||||||
|
for (LwjglDevice device : context.getDevices()) { |
||||||
|
CLDevice d = device.getDevice(); |
||||||
|
str.append(device.getName()).append(":\n"); |
||||||
|
str.append(program.getBuildInfoString(d, CL10.CL_PROGRAM_BUILD_LOG)); |
||||||
|
str.append('\n'); |
||||||
|
} |
||||||
|
return str.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Kernel createKernel(String name) { |
||||||
|
CLKernel kernel = CL10.clCreateKernel(program, name, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateKernel"); |
||||||
|
return new LwjglKernel(kernel); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Kernel[] createAllKernels() { |
||||||
|
CLKernel[] kernels = program.createKernelsInProgram(); |
||||||
|
Kernel[] kx = new Kernel[kernels.length]; |
||||||
|
for (int i=0; i<kernels.length; ++i) { |
||||||
|
kx[i] = new LwjglKernel(kernels[i]); |
||||||
|
} |
||||||
|
return kx; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ByteBuffer getBinary(Device device) { |
||||||
|
ByteBuffer[] binaries = program.getInfoBinaries((ByteBuffer[]) null); |
||||||
|
CLDevice[] devices = program.getInfoDevices(); |
||||||
|
//find the requested one
|
||||||
|
assert (binaries.length == devices.length); |
||||||
|
for (int i=0; i<devices.length; ++i) { |
||||||
|
if (((LwjglDevice) device).device == devices[i]) { |
||||||
|
return binaries[i]; |
||||||
|
} |
||||||
|
} |
||||||
|
throw new com.jme3.opencl.OpenCLException("Program was not built against the specified device "+device); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private CLProgram program; |
||||||
|
private ReleaserImpl(CLProgram program) { |
||||||
|
this.program = program; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
//LWJGL Bug: releasing a program also released every! kernel associated with that program
|
||||||
|
/* |
||||||
|
if (program != null) { |
||||||
|
int ret = CL10.clReleaseProgram(program); |
||||||
|
program = null; |
||||||
|
Utils.reportError(ret, "clReleaseProgram"); |
||||||
|
} |
||||||
|
*/ |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,167 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.MappingAccess; |
||||||
|
import com.jme3.opencl.MemoryAccess; |
||||||
|
import com.jme3.opencl.OpenCLException; |
||||||
|
import java.lang.reflect.Field; |
||||||
|
import java.nio.*; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import org.lwjgl.BufferUtils; |
||||||
|
import org.lwjgl.LWJGLUtil; |
||||||
|
import org.lwjgl.PointerBuffer; |
||||||
|
import org.lwjgl.opencl.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class Utils { |
||||||
|
private static final Logger LOG = Logger.getLogger(Utils.class.getName()); |
||||||
|
private Utils() {} |
||||||
|
|
||||||
|
/** Maps OpenCL error token values to their String representations. |
||||||
|
Taken directly from org.lwjgl.opencl.Util |
||||||
|
*/ |
||||||
|
private static final Map<Integer, String> CL_ERROR_TOKENS = LWJGLUtil.getClassTokens(new LWJGLUtil.TokenFilter() { |
||||||
|
public boolean accept(final Field field, final int value) { |
||||||
|
return value < 0; // Currently, all OpenCL errors have negative values.
|
||||||
|
} |
||||||
|
}, null, CL10.class, CL11.class, CL12.class, KHRGLSharing.class, KHRICD.class, APPLEGLSharing.class, EXTDeviceFission.class); |
||||||
|
|
||||||
|
public static int getMajorVersion(String version, String prefix) { |
||||||
|
String s = version.substring(prefix.length()); |
||||||
|
return Integer.parseInt(s); |
||||||
|
} |
||||||
|
|
||||||
|
public static int getMinorVersion(String version, String prefix) { |
||||||
|
String s = version.substring(prefix.length()); |
||||||
|
int major = Integer.parseInt(s); |
||||||
|
s = s.substring((int) (Math.log10(major) + 2)); |
||||||
|
return Integer.parseInt(s); |
||||||
|
} |
||||||
|
|
||||||
|
public static final class TempBuffer { |
||||||
|
public final ByteBuffer b16; |
||||||
|
public final ShortBuffer b16s; |
||||||
|
public final IntBuffer b16i; |
||||||
|
public final LongBuffer b16l; |
||||||
|
public final FloatBuffer b16f; |
||||||
|
public final DoubleBuffer b16d; |
||||||
|
public TempBuffer() { |
||||||
|
b16 = BufferUtils.createByteBuffer(16); |
||||||
|
b16s = b16.asShortBuffer(); |
||||||
|
b16i = b16.asIntBuffer(); |
||||||
|
b16l = b16.asLongBuffer(); |
||||||
|
b16f = b16.asFloatBuffer(); |
||||||
|
b16d = b16.asDoubleBuffer(); |
||||||
|
} |
||||||
|
} |
||||||
|
public static final ByteBuffer b80; //needed for ImageDescriptor and Matrix4f
|
||||||
|
public static final LongBuffer b80l; |
||||||
|
public static final FloatBuffer b80f; |
||||||
|
public static final TempBuffer[] tempBuffers = new TempBuffer[8]; |
||||||
|
public static final PointerBuffer[] pointerBuffers = new PointerBuffer[8]; |
||||||
|
static { |
||||||
|
for (int i=0; i<8; ++i) { |
||||||
|
tempBuffers[i] = new TempBuffer(); |
||||||
|
pointerBuffers[i] = PointerBuffer.allocateDirect(4); |
||||||
|
} |
||||||
|
errorBuffer = BufferUtils.createIntBuffer(1); |
||||||
|
b80 = BufferUtils.createByteBuffer(80); |
||||||
|
b80l = b80.asLongBuffer(); |
||||||
|
b80f = b80.asFloatBuffer(); |
||||||
|
} |
||||||
|
|
||||||
|
public static IntBuffer errorBuffer; |
||||||
|
public static void checkError(IntBuffer errorBuffer, String callName) { |
||||||
|
checkError(errorBuffer.get(0), callName); |
||||||
|
} |
||||||
|
public static void checkError(int error, String callName) { |
||||||
|
if (error != CL10.CL_SUCCESS) { |
||||||
|
String errname = getErrorName(error); |
||||||
|
if (errname == null) { |
||||||
|
errname = "UNKNOWN"; |
||||||
|
} |
||||||
|
throw new OpenCLException("OpenCL error in " + callName + ": " + errname + " (0x" + Integer.toHexString(error) + ")", error); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void reportError(int error, String callName) { |
||||||
|
if (error != CL10.CL_SUCCESS) { |
||||||
|
String errname = getErrorName(error); |
||||||
|
if (errname == null) { |
||||||
|
errname = "UNKNOWN"; |
||||||
|
} |
||||||
|
LOG.log(Level.WARNING, "OpenCL error in {0}: {1} (0x{2})", new Object[]{callName, errname, Integer.toHexString(error)}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static String getErrorName(int code) { |
||||||
|
return CL_ERROR_TOKENS.get(code); |
||||||
|
} |
||||||
|
|
||||||
|
public static long getMemoryAccessFlags(MemoryAccess ma) { |
||||||
|
switch (ma) { |
||||||
|
case READ_ONLY: return CL10.CL_MEM_READ_ONLY; |
||||||
|
case WRITE_ONLY: return CL10.CL_MEM_WRITE_ONLY; |
||||||
|
case READ_WRITE: return CL10.CL_MEM_READ_WRITE; |
||||||
|
default: throw new IllegalArgumentException("Unknown memory access: "+ma); |
||||||
|
} |
||||||
|
} |
||||||
|
public static MemoryAccess getMemoryAccessFromFlag(long flag) { |
||||||
|
if ((flag & CL10.CL_MEM_READ_WRITE) > 0) { |
||||||
|
return MemoryAccess.READ_WRITE; |
||||||
|
} |
||||||
|
if ((flag & CL10.CL_MEM_READ_ONLY) > 0) { |
||||||
|
return MemoryAccess.READ_ONLY; |
||||||
|
} |
||||||
|
if ((flag & CL10.CL_MEM_WRITE_ONLY) > 0) { |
||||||
|
return MemoryAccess.WRITE_ONLY; |
||||||
|
} |
||||||
|
throw new OpenCLException("Unknown memory access flag: "+flag); |
||||||
|
} |
||||||
|
|
||||||
|
public static long getMappingAccessFlags(MappingAccess ma) { |
||||||
|
switch (ma) { |
||||||
|
case MAP_READ_ONLY: return CL10.CL_MAP_READ; |
||||||
|
case MAP_READ_WRITE: return CL10.CL_MAP_READ | CL10.CL_MAP_WRITE; |
||||||
|
case MAP_WRITE_ONLY: return CL10.CL_MAP_WRITE; |
||||||
|
case MAP_WRITE_INVALIDATE: return CL12.CL_MAP_WRITE_INVALIDATE_REGION; |
||||||
|
default: throw new IllegalArgumentException("Unknown mapping access: "+ma); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,238 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.*; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import org.lwjgl.opencl.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class LwjglBuffer extends Buffer { |
||||||
|
|
||||||
|
private final long buffer; |
||||||
|
|
||||||
|
public LwjglBuffer(long buffer) { |
||||||
|
super(new ReleaserImpl(buffer)); |
||||||
|
this.buffer = buffer; |
||||||
|
} |
||||||
|
public long getBuffer() { |
||||||
|
return buffer; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getSize() { |
||||||
|
return Info.clGetMemObjectInfoLong(buffer, CL10.CL_MEM_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public MemoryAccess getMemoryAccessFlags() { |
||||||
|
return Utils.getMemoryAccessFromFlag(Info.clGetMemObjectInfoLong(buffer, CL10.CL_MEM_FLAGS)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void read(CommandQueue queue, ByteBuffer dest, long size, long offset) { |
||||||
|
//Note: LWJGL does not support the size parameter, I have to set the buffer limit
|
||||||
|
dest.limit((int) (dest.position() + size)); |
||||||
|
int ret = CL10.clEnqueueReadBuffer(((LwjglCommandQueue)queue).getQueue(), |
||||||
|
buffer, CL10.CL_TRUE, offset, dest, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueReadBuffer"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event readAsync(CommandQueue queue, ByteBuffer dest, long size, long offset) { |
||||||
|
//Note: LWJGL does not support the size parameter, I have to set the buffer limit
|
||||||
|
dest.limit((int) (dest.position() + size)); |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
long q = ((LwjglCommandQueue)queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueReadBuffer(q, buffer, CL10.CL_FALSE, offset, dest, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueReadBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void write(CommandQueue queue, ByteBuffer src, long size, long offset) { |
||||||
|
//Note: LWJGL does not support the size parameter, I have to set the buffer limit
|
||||||
|
src.limit((int) (src.position() + size)); |
||||||
|
long q = ((LwjglCommandQueue)queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueWriteBuffer(q, buffer, CL10.CL_TRUE, offset, src, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueWriteBuffer"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event writeAsync(CommandQueue queue, ByteBuffer src, long size, long offset) { |
||||||
|
//Note: LWJGL does not support the size parameter, I have to set the buffer limit
|
||||||
|
src.limit((int) (src.position() + size)); |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
long q = ((LwjglCommandQueue)queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueWriteBuffer(q, buffer, CL10.CL_FALSE, offset, src, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueWriteBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void copyTo(CommandQueue queue, Buffer dest, long size, long srcOffset, long destOffset) { |
||||||
|
long q = ((LwjglCommandQueue)queue).getQueue(); |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
int ret = CL10.clEnqueueCopyBuffer(q, buffer, ((LwjglBuffer) dest).buffer, srcOffset, destOffset, size, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
ret = CL10.clWaitForEvents(event); |
||||||
|
Utils.checkError(ret, "clWaitForEvents"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event copyToAsync(CommandQueue queue, Buffer dest, long size, long srcOffset, long destOffset) { |
||||||
|
long q = ((LwjglCommandQueue)queue).getQueue(); |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
int ret = CL10.clEnqueueCopyBuffer(q, buffer, ((LwjglBuffer) dest).buffer, srcOffset, destOffset, size, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ByteBuffer map(CommandQueue queue, long size, long offset, MappingAccess access) { |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
long flags = Utils.getMappingAccessFlags(access); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
ByteBuffer b = CL10.clEnqueueMapBuffer(q, buffer, CL10.CL_TRUE, flags, offset, size, null, null, Utils.errorBuffer, null); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer"); |
||||||
|
return b; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void unmap(CommandQueue queue, ByteBuffer ptr) { |
||||||
|
ptr.position(0); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
int ret = CL10.clEnqueueUnmapMemObject(q, buffer, ptr, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueUnmapMemObject"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
ret = CL10.clWaitForEvents(event); |
||||||
|
Utils.checkError(ret, "clWaitForEvents"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public com.jme3.opencl.Buffer.AsyncMapping mapAsync(CommandQueue queue, long size, long offset, MappingAccess access) { |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
long flags = Utils.getMappingAccessFlags(access); |
||||||
|
ByteBuffer buf = CL10.clEnqueueMapBuffer(q, buffer, CL10.CL_FALSE, flags, offset, size, null, Utils.pointerBuffers[0], Utils.errorBuffer, null); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new com.jme3.opencl.Buffer.AsyncMapping(new LwjglEvent(event), buf); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event fillAsync(CommandQueue queue, ByteBuffer pattern, long size, long offset) { |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL12.clEnqueueFillBuffer(q, buffer, pattern, offset, size, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueFillBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event copyToImageAsync(CommandQueue queue, Image dest, long srcOffset, long[] destOrigin, long[] destRegion) { |
||||||
|
if (destOrigin.length!=3 || destRegion.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(destOrigin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(destRegion).position(0); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueCopyBufferToImage(q, buffer, ((LwjglImage) dest).getImage(), |
||||||
|
srcOffset, Utils.pointerBuffers[1], Utils.pointerBuffers[2], null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyBufferToImage"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event acquireBufferForSharingAsync(CommandQueue queue) { |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueAcquireGLObjects(q, buffer, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueAcquireGLObjects"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(event); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void acquireBufferForSharingNoEvent(CommandQueue queue) { |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueAcquireGLObjects(q, buffer, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueAcquireGLObjects"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event releaseBufferForSharingAsync(CommandQueue queue) { |
||||||
|
Utils.assertSharingPossible(); |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueReleaseGLObjects(q, buffer, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueReleaseGLObjects"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(event); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void releaseBufferForSharingNoEvent(CommandQueue queue) { |
||||||
|
Utils.assertSharingPossible(); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueReleaseGLObjects(q, buffer, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueReleaseGLObjects"); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private long mem; |
||||||
|
private ReleaserImpl(long mem) { |
||||||
|
this.mem = mem; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (mem != 0) { |
||||||
|
int ret = CL10.clReleaseMemObject(mem); |
||||||
|
mem = 0; |
||||||
|
Utils.reportError(ret, "clReleaseMemObject"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,80 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.CommandQueue; |
||||||
|
import org.lwjgl.opencl.CL10; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class LwjglCommandQueue extends CommandQueue { |
||||||
|
|
||||||
|
private final long queue; |
||||||
|
|
||||||
|
public LwjglCommandQueue(long queue) { |
||||||
|
super(new ReleaserImpl(queue)); |
||||||
|
this.queue = queue; |
||||||
|
} |
||||||
|
|
||||||
|
public long getQueue() { |
||||||
|
return queue; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void flush() { |
||||||
|
int ret = CL10.clFlush(queue); |
||||||
|
Utils.checkError(ret, "clFlush"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void finish() { |
||||||
|
int ret = CL10.clFinish(queue); |
||||||
|
Utils.checkError(ret, "clFinish"); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private long queue; |
||||||
|
private ReleaserImpl(long queue) { |
||||||
|
this.queue = queue; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (queue != 0) { |
||||||
|
int ret = CL10.clReleaseCommandQueue(queue); |
||||||
|
queue = 0; |
||||||
|
Utils.reportError(ret, "clReleaseCommandQueue"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,255 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.*; |
||||||
|
import com.jme3.opencl.Context; |
||||||
|
import com.jme3.opencl.Image.ImageDescriptor; |
||||||
|
import com.jme3.opencl.Image.ImageFormat; |
||||||
|
import com.jme3.scene.VertexBuffer; |
||||||
|
import com.jme3.texture.FrameBuffer; |
||||||
|
import com.jme3.texture.Texture; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.nio.IntBuffer; |
||||||
|
import java.util.List; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import org.lwjgl.BufferUtils; |
||||||
|
import org.lwjgl.opencl.*; |
||||||
|
import org.lwjgl.opengl.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class LwjglContext extends Context { |
||||||
|
private static final Logger LOG = Logger.getLogger(LwjglContext.class.getName()); |
||||||
|
private final long context; |
||||||
|
private final List<LwjglDevice> devices; |
||||||
|
|
||||||
|
public LwjglContext(long context, List<LwjglDevice> devices) { |
||||||
|
super(new ReleaserImpl(context, devices)); |
||||||
|
this.context = context; |
||||||
|
this.devices = devices; |
||||||
|
} |
||||||
|
|
||||||
|
public long getContext() { |
||||||
|
return context; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<LwjglDevice> getDevices() { |
||||||
|
return devices; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
@SuppressWarnings("element-type-mismatch") |
||||||
|
public CommandQueue createQueue(Device device) { |
||||||
|
assert (devices.contains(device)); //this also ensures that device is a LwjglDevice
|
||||||
|
long d = ((LwjglDevice) device).getDevice(); |
||||||
|
long properties = 0; |
||||||
|
long q = CL10.clCreateCommandQueue(context, d, properties, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateCommandQueue"); |
||||||
|
return new LwjglCommandQueue(q); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Buffer createBuffer(long size, MemoryAccess access) { |
||||||
|
long flags = Utils.getMemoryAccessFlags(access); |
||||||
|
long mem = CL10.clCreateBuffer(context, flags, size, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateBuffer"); |
||||||
|
return new LwjglBuffer(mem); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Buffer createBufferFromHost(ByteBuffer data, MemoryAccess access) { |
||||||
|
long flags = Utils.getMemoryAccessFlags(access); |
||||||
|
flags |= CL10.CL_MEM_USE_HOST_PTR; |
||||||
|
long mem = CL10.clCreateBuffer(context, flags, data, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateBuffer"); |
||||||
|
return new LwjglBuffer(mem); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Image createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr) { |
||||||
|
long memFlags = Utils.getMemoryAccessFlags(access); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
|
||||||
|
CLImageFormat f = null; |
||||||
|
CLImageDesc d = null; |
||||||
|
try { |
||||||
|
f = CLImageFormat.malloc(); |
||||||
|
d = CLImageDesc.calloc(); |
||||||
|
f.image_channel_data_type(LwjglImage.decodeImageChannelType(format.channelType)); |
||||||
|
f.image_channel_order(LwjglImage.decodeImageChannelOrder(format.channelOrder)); |
||||||
|
d.image_type(LwjglImage.decodeImageType(descr.type)); |
||||||
|
d.image_width(descr.width); |
||||||
|
d.image_height(descr.height); |
||||||
|
d.image_depth(descr.depth); |
||||||
|
d.image_array_size(descr.arraySize); |
||||||
|
d.image_row_pitch(descr.rowPitch); |
||||||
|
d.image_slice_pitch(descr.slicePitch); |
||||||
|
//create image
|
||||||
|
long mem = CL12.clCreateImage(context, memFlags, f, d, descr.hostPtr, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateImage"); |
||||||
|
return new LwjglImage(mem); |
||||||
|
} finally { |
||||||
|
if (f != null) { |
||||||
|
f.free(); |
||||||
|
} |
||||||
|
if (d != null) { |
||||||
|
d.free(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageFormat[] querySupportedFormats(MemoryAccess access, Image.ImageType type) { |
||||||
|
long memFlags = Utils.getMemoryAccessFlags(access); |
||||||
|
int typeFlag = LwjglImage.decodeImageType(type); |
||||||
|
Utils.tempBuffers[0].b16i.rewind(); |
||||||
|
//query count
|
||||||
|
int ret = CL10.clGetSupportedImageFormats(context, memFlags, typeFlag, null, Utils.tempBuffers[0].b16i); |
||||||
|
Utils.checkError(ret, "clGetSupportedImageFormats"); |
||||||
|
int count = Utils.tempBuffers[0].b16i.get(0); |
||||||
|
if (count == 0) { |
||||||
|
return new ImageFormat[0]; |
||||||
|
} |
||||||
|
//get formats
|
||||||
|
CLImageFormat.Buffer formatsB = new CLImageFormat.Buffer(BufferUtils.createByteBuffer(count * CLImageFormat.SIZEOF)); |
||||||
|
ret = CL10.clGetSupportedImageFormats(context, memFlags, typeFlag, formatsB, null); |
||||||
|
Utils.checkError(ret, "clGetSupportedImageFormats"); |
||||||
|
//convert formats
|
||||||
|
ImageFormat[] formats = new ImageFormat[count]; |
||||||
|
for (int i=0; i<count; ++i) { |
||||||
|
CLImageFormat f = formatsB.get(); |
||||||
|
Image.ImageChannelOrder channelOrder = LwjglImage.encodeImageChannelOrder(f.image_channel_order()); |
||||||
|
Image.ImageChannelType channelType = LwjglImage.encodeImageChannelType(f.image_channel_data_type()); |
||||||
|
formats[i] = new ImageFormat(channelOrder, channelType); |
||||||
|
} |
||||||
|
return formats; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Buffer bindVertexBuffer(VertexBuffer vb, MemoryAccess access) { |
||||||
|
Utils.assertSharingPossible(); |
||||||
|
int id = vb.getId(); |
||||||
|
if (id == -1) { |
||||||
|
throw new IllegalArgumentException("vertex buffer was not yet uploaded to the GPU or is CPU only"); |
||||||
|
} |
||||||
|
long flags = Utils.getMemoryAccessFlags(access); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
long mem = CL10GL.clCreateFromGLBuffer(context, flags, id, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateFromGLBuffer"); |
||||||
|
return new LwjglBuffer(mem); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Image bindImage(com.jme3.texture.Image image, Texture.Type textureType, int miplevel, MemoryAccess access) { |
||||||
|
Utils.assertSharingPossible(); |
||||||
|
int imageID = image.getId(); |
||||||
|
if (imageID == -1) { |
||||||
|
throw new IllegalArgumentException("image was not yet uploaded to the GPU"); |
||||||
|
} |
||||||
|
long memFlags = Utils.getMemoryAccessFlags(access); |
||||||
|
int textureTarget = convertTextureType(textureType); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
long mem = CL12GL.clCreateFromGLTexture(context, memFlags, textureTarget, miplevel, imageID, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateFromGLTexture"); |
||||||
|
return new LwjglImage(mem); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Image bindPureRenderBuffer(FrameBuffer.RenderBuffer buffer, MemoryAccess access) { |
||||||
|
Utils.assertSharingPossible(); |
||||||
|
int renderbuffer = buffer.getId(); |
||||||
|
if (renderbuffer == -1) { |
||||||
|
throw new IllegalArgumentException("renderbuffer was not yet uploaded to the GPU"); |
||||||
|
} |
||||||
|
long memFlags = Utils.getMemoryAccessFlags(access); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
long mem = CL10GL.clCreateFromGLRenderbuffer(context, memFlags, renderbuffer, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateFromGLRenderbuffer"); |
||||||
|
return new LwjglImage(mem); |
||||||
|
} |
||||||
|
|
||||||
|
private int convertTextureType(Texture.Type textureType) { |
||||||
|
switch (textureType) { |
||||||
|
case TwoDimensional: return GL11.GL_TEXTURE_2D; |
||||||
|
case TwoDimensionalArray: return GL30.GL_TEXTURE_2D_ARRAY; |
||||||
|
case ThreeDimensional: return GL12.GL_TEXTURE_3D; |
||||||
|
case CubeMap: return GL13.GL_TEXTURE_CUBE_MAP; |
||||||
|
default: throw new IllegalArgumentException("unknown texture type "+textureType); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Program createProgramFromSourceCode(String sourceCode) { |
||||||
|
LOG.log(Level.FINE, "Create program from source:\n{0}", sourceCode); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
long p = CL10.clCreateProgramWithSource(context, sourceCode, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateProgramWithSource"); |
||||||
|
return new LwjglProgram(p, this); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Program createProgramFromBinary(ByteBuffer binaries, Device device) { |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
Utils.tempBuffers[0].b16i.rewind(); |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[0].put(0, ((LwjglDevice) device).getDevice()); |
||||||
|
long p = CL10.clCreateProgramWithBinary(context, Utils.pointerBuffers[0], |
||||||
|
binaries, Utils.tempBuffers[0].b16i, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateProgramWithBinary"); |
||||||
|
Utils.checkError(Utils.tempBuffers[0].b16i, "clCreateProgramWithBinary"); |
||||||
|
return new LwjglProgram(p, this); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private long context; |
||||||
|
private final List<LwjglDevice> devices; |
||||||
|
private ReleaserImpl(long mem, List<LwjglDevice> devices) { |
||||||
|
this.context = mem; |
||||||
|
this.devices = devices; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (context != 0) { |
||||||
|
int ret = CL10.clReleaseContext(context); |
||||||
|
context = 0; |
||||||
|
devices.clear(); |
||||||
|
Utils.reportError(ret, "clReleaseMemObject"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,303 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.Device; |
||||||
|
import com.jme3.opencl.Platform; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Collection; |
||||||
|
import org.lwjgl.PointerBuffer; |
||||||
|
import org.lwjgl.opencl.CL10; |
||||||
|
import org.lwjgl.opencl.CL11; |
||||||
|
import org.lwjgl.opencl.CLDevice; |
||||||
|
import org.lwjgl.opencl.Info; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public final class LwjglDevice implements Device { |
||||||
|
|
||||||
|
final CLDevice device; |
||||||
|
final LwjglPlatform platform; |
||||||
|
|
||||||
|
public LwjglDevice(CLDevice device, LwjglPlatform platform) { |
||||||
|
this.device = device; |
||||||
|
this.platform = platform; |
||||||
|
} |
||||||
|
|
||||||
|
public long getDevice() { |
||||||
|
return device.address(); |
||||||
|
} |
||||||
|
public CLDevice getCLDevice() { |
||||||
|
return device; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public LwjglPlatform getPlatform() { |
||||||
|
return platform; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public DeviceType getDeviceType() { |
||||||
|
int type = Info.clGetDeviceInfoInt(device.address(), CL10.CL_DEVICE_TYPE); |
||||||
|
switch (type) { |
||||||
|
case CL10.CL_DEVICE_TYPE_ACCELERATOR: return DeviceType.ACCELEARTOR; |
||||||
|
case CL10.CL_DEVICE_TYPE_CPU: return DeviceType.CPU; |
||||||
|
case CL10.CL_DEVICE_TYPE_GPU: return DeviceType.GPU; |
||||||
|
default: return DeviceType.DEFAULT; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getVendorId() { |
||||||
|
return Info.clGetDeviceInfoInt(device.address(), CL10.CL_DEVICE_VENDOR_ID); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isAvailable() { |
||||||
|
return Info.clGetDeviceInfoBoolean(device.address(), CL10.CL_DEVICE_AVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasCompiler() { |
||||||
|
return Info.clGetDeviceInfoBoolean(device.address(), CL10.CL_DEVICE_COMPILER_AVAILABLE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasDouble() { |
||||||
|
return hasExtension("cl_khr_fp64"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasHalfFloat() { |
||||||
|
return hasExtension("cl_khr_fp16"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasErrorCorrectingMemory() { |
||||||
|
return Info.clGetDeviceInfoBoolean(device.address(), CL10.CL_DEVICE_ERROR_CORRECTION_SUPPORT); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasUnifiedMemory() { |
||||||
|
return Info.clGetDeviceInfoBoolean(device.address(), CL11.CL_DEVICE_HOST_UNIFIED_MEMORY); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasImageSupport() { |
||||||
|
return Info.clGetDeviceInfoBoolean(device.address(), CL10.CL_DEVICE_IMAGE_SUPPORT); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasWritableImage3D() { |
||||||
|
return hasExtension("cl_khr_3d_image_writes"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasOpenGLInterop() { |
||||||
|
return hasExtension("cl_khr_gl_sharing"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasExtension(String extension) { |
||||||
|
return getExtensions().contains(extension); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Collection<? extends String> getExtensions() { |
||||||
|
return Arrays.asList(Info.clGetDeviceInfoStringASCII(device.address(), CL10.CL_DEVICE_EXTENSIONS).split(" ")); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getComputeUnits() { |
||||||
|
return Info.clGetDeviceInfoInt(device.address(), CL10.CL_DEVICE_MAX_COMPUTE_UNITS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getClockFrequency() { |
||||||
|
return Info.clGetDeviceInfoInt(device.address(), CL10.CL_DEVICE_MAX_CLOCK_FREQUENCY); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getAddressBits() { |
||||||
|
return Info.clGetDeviceInfoInt(device.address(), CL10.CL_DEVICE_ADDRESS_BITS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isLittleEndian() { |
||||||
|
return Info.clGetDeviceInfoBoolean(device.address(), CL10.CL_DEVICE_ENDIAN_LITTLE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaximumWorkItemDimensions() { |
||||||
|
return Info.clGetDeviceInfoInt(device.address(), CL10.CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long[] getMaximumWorkItemSizes() { |
||||||
|
int dim = (int) getMaximumWorkItemDimensions(); |
||||||
|
PointerBuffer sizes = PointerBuffer.allocateDirect(dim); |
||||||
|
Info.clGetDeviceInfoPointers(device.address(), CL10.CL_DEVICE_MAX_WORK_ITEM_SIZES, sizes); |
||||||
|
long[] sx = new long[dim]; |
||||||
|
sizes.get(sx); |
||||||
|
return sx; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaxiumWorkItemsPerGroup() { |
||||||
|
return Info.clGetDeviceInfoPointer(device.address(), CL10.CL_DEVICE_MAX_WORK_GROUP_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getMaximumSamplers() { |
||||||
|
return Info.clGetDeviceInfoInt(device.address(), CL10.CL_DEVICE_MAX_SAMPLERS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getMaximumReadImages() { |
||||||
|
return Info.clGetDeviceInfoInt(device.address(), CL10.CL_DEVICE_MAX_READ_IMAGE_ARGS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getMaximumWriteImages() { |
||||||
|
return Info.clGetDeviceInfoInt(device.address(), CL10.CL_DEVICE_MAX_WRITE_IMAGE_ARGS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long[] getMaximumImage2DSize() { |
||||||
|
return new long[] { |
||||||
|
Info.clGetDeviceInfoPointer(device.address(), CL10.CL_DEVICE_IMAGE2D_MAX_WIDTH), |
||||||
|
Info.clGetDeviceInfoPointer(device.address(), CL10.CL_DEVICE_IMAGE2D_MAX_HEIGHT) |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long[] getMaximumImage3DSize() { |
||||||
|
return new long[] { |
||||||
|
Info.clGetDeviceInfoPointer(device.address(), CL10.CL_DEVICE_IMAGE3D_MAX_WIDTH), |
||||||
|
Info.clGetDeviceInfoPointer(device.address(), CL10.CL_DEVICE_IMAGE3D_MAX_HEIGHT), |
||||||
|
Info.clGetDeviceInfoPointer(device.address(), CL10.CL_DEVICE_IMAGE3D_MAX_DEPTH) |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaximumAllocationSize() { |
||||||
|
return Info.clGetDeviceInfoLong(device.address(), CL10.CL_DEVICE_MAX_MEM_ALLOC_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getGlobalMemorySize() { |
||||||
|
return Info.clGetDeviceInfoLong(device.address(), CL10.CL_DEVICE_GLOBAL_MEM_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getLocalMemorySize() { |
||||||
|
return Info.clGetDeviceInfoLong(device.address(), CL10.CL_DEVICE_LOCAL_MEM_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaximumConstantBufferSize() { |
||||||
|
return Info.clGetDeviceInfoLong(device.address(), CL10.CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getMaximumConstantArguments() { |
||||||
|
return Info.clGetDeviceInfoInt(device.address(), CL10.CL_DEVICE_MAX_CONSTANT_ARGS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getProfile() { |
||||||
|
return Info.clGetDeviceInfoStringASCII(device.address(), CL10.CL_DEVICE_PROFILE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getVersion() { |
||||||
|
return Info.clGetDeviceInfoStringASCII(device.address(), CL10.CL_DEVICE_VERSION); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getVersionMajor() { |
||||||
|
return Utils.getMajorVersion(getVersion(), "OpenCL "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getVersionMinor() { |
||||||
|
return Utils.getMinorVersion(getVersion(), "OpenCL "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getCompilerVersion() { |
||||||
|
return Info.clGetDeviceInfoStringASCII(device.address(), CL11.CL_DEVICE_OPENCL_C_VERSION); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getCompilerVersionMajor() { |
||||||
|
return Utils.getMajorVersion(getCompilerVersion(), "OpenCL C "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getCompilerVersionMinor() { |
||||||
|
return Utils.getMinorVersion(getCompilerVersion(), "OpenCL C "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getDriverVersion() { |
||||||
|
return Info.clGetDeviceInfoStringASCII(device.address(), CL10.CL_DRIVER_VERSION); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getDriverVersionMajor() { |
||||||
|
return Utils.getMajorVersion(getDriverVersion(), ""); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getDriverVersionMinor() { |
||||||
|
return Utils.getMinorVersion(getDriverVersion(), ""); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return Info.clGetDeviceInfoStringASCII(device.address(), CL10.CL_DEVICE_NAME); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getVendor() { |
||||||
|
return Info.clGetDeviceInfoStringASCII(device.address(), CL10.CL_DEVICE_VENDOR); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return getName(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,94 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.Event; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import org.lwjgl.opencl.CL10; |
||||||
|
import org.lwjgl.opencl.Info; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class LwjglEvent extends Event { |
||||||
|
private static final Logger LOG = Logger.getLogger(LwjglEvent.class.getName()); |
||||||
|
private long event; |
||||||
|
|
||||||
|
public LwjglEvent(long event) { |
||||||
|
super(new ReleaserImpl(event)); |
||||||
|
this.event = event; |
||||||
|
} |
||||||
|
|
||||||
|
public long getEvent() { |
||||||
|
return event; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void waitForFinished() { |
||||||
|
CL10.clWaitForEvents(event); |
||||||
|
release(); //short cut to save resources
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isCompleted() { |
||||||
|
int status = Info.clGetEventInfoInt(event, CL10.CL_EVENT_COMMAND_EXECUTION_STATUS); |
||||||
|
if (status == CL10.CL_SUCCESS) { |
||||||
|
release(); //short cut to save resources
|
||||||
|
return true; |
||||||
|
} else if (status < 0) { |
||||||
|
Utils.checkError(status, "EventStatus"); |
||||||
|
return false; |
||||||
|
} else { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private long event; |
||||||
|
|
||||||
|
private ReleaserImpl(long event) { |
||||||
|
this.event = event; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (event != 0) { |
||||||
|
int ret = CL10.clReleaseEvent(event); |
||||||
|
event = 0; |
||||||
|
Utils.reportError(ret, "clReleaseEvent"); |
||||||
|
LOG.finer("Event deleted"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,579 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.math.ColorRGBA; |
||||||
|
import com.jme3.opencl.*; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import org.lwjgl.opencl.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class LwjglImage extends Image { |
||||||
|
private static final Logger LOG = Logger.getLogger(LwjglImage.class.getName()); |
||||||
|
|
||||||
|
private final long image; |
||||||
|
|
||||||
|
public LwjglImage(long image) { |
||||||
|
super(new ReleaserImpl(image)); |
||||||
|
this.image = image; |
||||||
|
} |
||||||
|
|
||||||
|
public long getImage() { |
||||||
|
return image; |
||||||
|
} |
||||||
|
|
||||||
|
public static int decodeImageChannelOrder(ImageChannelOrder order) { |
||||||
|
switch (order) { |
||||||
|
case A: |
||||||
|
return CL10.CL_A; |
||||||
|
case ARGB: |
||||||
|
return CL10.CL_ARGB; |
||||||
|
case BGRA: |
||||||
|
return CL10.CL_BGRA; |
||||||
|
case INTENSITY: |
||||||
|
return CL10.CL_INTENSITY; |
||||||
|
case LUMINANCE: |
||||||
|
return CL10.CL_LUMINANCE; |
||||||
|
case R: |
||||||
|
return CL10.CL_R; |
||||||
|
case RA: |
||||||
|
return CL10.CL_RA; |
||||||
|
case RG: |
||||||
|
return CL10.CL_RG; |
||||||
|
case RGB: |
||||||
|
return CL10.CL_RGB; |
||||||
|
case RGBA: |
||||||
|
return CL10.CL_RGBA; |
||||||
|
case RGBx: |
||||||
|
return CL11.CL_RGBx; |
||||||
|
case RGx: |
||||||
|
return CL11.CL_RGx; |
||||||
|
case Rx: |
||||||
|
return CL11.CL_Rx; |
||||||
|
default: |
||||||
|
throw new IllegalArgumentException("unknown image channel order: " + order); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static ImageChannelOrder encodeImageChannelOrder(int order) { |
||||||
|
switch (order) { |
||||||
|
case CL10.CL_A: |
||||||
|
return ImageChannelOrder.A; |
||||||
|
case CL10.CL_ARGB: |
||||||
|
return ImageChannelOrder.ARGB; |
||||||
|
case CL10.CL_BGRA: |
||||||
|
return ImageChannelOrder.BGRA; |
||||||
|
case CL10.CL_INTENSITY: |
||||||
|
return ImageChannelOrder.INTENSITY; |
||||||
|
case CL10.CL_LUMINANCE: |
||||||
|
return ImageChannelOrder.LUMINANCE; |
||||||
|
case CL10.CL_R: |
||||||
|
return ImageChannelOrder.R; |
||||||
|
case CL10.CL_RA: |
||||||
|
return ImageChannelOrder.RA; |
||||||
|
case CL10.CL_RG: |
||||||
|
return ImageChannelOrder.RG; |
||||||
|
case CL10.CL_RGB: |
||||||
|
return ImageChannelOrder.RGB; |
||||||
|
case CL10.CL_RGBA: |
||||||
|
return ImageChannelOrder.RGBA; |
||||||
|
case CL11.CL_RGBx: |
||||||
|
return ImageChannelOrder.RGBx; |
||||||
|
case CL11.CL_RGx: |
||||||
|
return ImageChannelOrder.RGx; |
||||||
|
case CL11.CL_Rx: |
||||||
|
return ImageChannelOrder.Rx; |
||||||
|
default: |
||||||
|
//throw new com.jme3.opencl.OpenCLException("unknown image channel order id: " + order);
|
||||||
|
LOG.log(Level.WARNING, "Unknown image channel order id: {0}", order); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static int decodeImageChannelType(ImageChannelType type) { |
||||||
|
switch (type) { |
||||||
|
case FLOAT: |
||||||
|
return CL10.CL_FLOAT; |
||||||
|
case HALF_FLOAT: |
||||||
|
return CL10.CL_HALF_FLOAT; |
||||||
|
case SIGNED_INT16: |
||||||
|
return CL10.CL_SIGNED_INT16; |
||||||
|
case SIGNED_INT32: |
||||||
|
return CL10.CL_SIGNED_INT32; |
||||||
|
case SIGNED_INT8: |
||||||
|
return CL10.CL_SIGNED_INT8; |
||||||
|
case SNORM_INT16: |
||||||
|
return CL10.CL_SNORM_INT16; |
||||||
|
case SNORM_INT8: |
||||||
|
return CL10.CL_SNORM_INT8; |
||||||
|
case UNORM_INT8: |
||||||
|
return CL10.CL_UNORM_INT8; |
||||||
|
case UNORM_INT_101010: |
||||||
|
return CL10.CL_UNORM_INT_101010; |
||||||
|
case UNORM_INT16: |
||||||
|
return CL10.CL_UNORM_INT16; |
||||||
|
case UNORM_SHORT_565: |
||||||
|
return CL10.CL_UNORM_SHORT_565; |
||||||
|
case UNORM_SHORT_555: |
||||||
|
return CL10.CL_UNORM_SHORT_555; |
||||||
|
case UNSIGNED_INT16: |
||||||
|
return CL10.CL_UNSIGNED_INT16; |
||||||
|
case UNSIGNED_INT32: |
||||||
|
return CL10.CL_UNSIGNED_INT32; |
||||||
|
case UNSIGNED_INT8: |
||||||
|
return CL10.CL_UNSIGNED_INT8; |
||||||
|
default: |
||||||
|
throw new IllegalArgumentException("Unknown image channel type: " + type); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static ImageChannelType encodeImageChannelType(int type) { |
||||||
|
switch (type) { |
||||||
|
case CL10.CL_FLOAT: |
||||||
|
return ImageChannelType.FLOAT; |
||||||
|
case CL10.CL_HALF_FLOAT: |
||||||
|
return ImageChannelType.HALF_FLOAT; |
||||||
|
case CL10.CL_SIGNED_INT16: |
||||||
|
return ImageChannelType.SIGNED_INT16; |
||||||
|
case CL10.CL_SIGNED_INT32: |
||||||
|
return ImageChannelType.SIGNED_INT32; |
||||||
|
case CL10.CL_SIGNED_INT8: |
||||||
|
return ImageChannelType.SIGNED_INT8; |
||||||
|
case CL10.CL_SNORM_INT16: |
||||||
|
return ImageChannelType.SNORM_INT16; |
||||||
|
case CL10.CL_SNORM_INT8: |
||||||
|
return ImageChannelType.SNORM_INT8; |
||||||
|
case CL10.CL_UNORM_INT8: |
||||||
|
return ImageChannelType.UNORM_INT8; |
||||||
|
case CL10.CL_UNORM_INT16: |
||||||
|
return ImageChannelType.UNORM_INT16; |
||||||
|
case CL10.CL_UNORM_INT_101010: |
||||||
|
return ImageChannelType.UNORM_INT_101010; |
||||||
|
case CL10.CL_UNORM_SHORT_555: |
||||||
|
return ImageChannelType.UNORM_SHORT_555; |
||||||
|
case CL10.CL_UNORM_SHORT_565: |
||||||
|
return ImageChannelType.UNORM_SHORT_565; |
||||||
|
case CL10.CL_UNSIGNED_INT16: |
||||||
|
return ImageChannelType.UNSIGNED_INT16; |
||||||
|
case CL10.CL_UNSIGNED_INT32: |
||||||
|
return ImageChannelType.UNSIGNED_INT32; |
||||||
|
case CL10.CL_UNSIGNED_INT8: |
||||||
|
return ImageChannelType.UNSIGNED_INT8; |
||||||
|
default: |
||||||
|
//throw new com.jme3.opencl.OpenCLException("unknown image channel type id: " + type);
|
||||||
|
LOG.log(Level.WARNING, "Unknown image channel type id: {0}", type); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static int decodeImageType(ImageType type) { |
||||||
|
switch (type) { |
||||||
|
case IMAGE_1D: |
||||||
|
return CL12.CL_MEM_OBJECT_IMAGE1D; |
||||||
|
case IMAGE_1D_ARRAY: |
||||||
|
return CL12.CL_MEM_OBJECT_IMAGE1D_ARRAY; |
||||||
|
case IMAGE_1D_BUFFER: |
||||||
|
return CL12.CL_MEM_OBJECT_IMAGE1D_BUFFER; |
||||||
|
case IMAGE_2D: |
||||||
|
return CL10.CL_MEM_OBJECT_IMAGE2D; |
||||||
|
case IMAGE_2D_ARRAY: |
||||||
|
return CL12.CL_MEM_OBJECT_IMAGE2D_ARRAY; |
||||||
|
case IMAGE_3D: |
||||||
|
return CL10.CL_MEM_OBJECT_IMAGE3D; |
||||||
|
default: |
||||||
|
throw new IllegalArgumentException("Unknown image type: " + type); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static ImageType encodeImageType(int type) { |
||||||
|
switch (type) { |
||||||
|
case CL12.CL_MEM_OBJECT_IMAGE1D: |
||||||
|
return ImageType.IMAGE_1D; |
||||||
|
case CL12.CL_MEM_OBJECT_IMAGE1D_ARRAY: |
||||||
|
return ImageType.IMAGE_1D_ARRAY; |
||||||
|
case CL12.CL_MEM_OBJECT_IMAGE1D_BUFFER: |
||||||
|
return ImageType.IMAGE_1D_BUFFER; |
||||||
|
case CL10.CL_MEM_OBJECT_IMAGE2D: |
||||||
|
return ImageType.IMAGE_2D; |
||||||
|
case CL12.CL_MEM_OBJECT_IMAGE2D_ARRAY: |
||||||
|
return ImageType.IMAGE_2D_ARRAY; |
||||||
|
case CL10.CL_MEM_OBJECT_IMAGE3D: |
||||||
|
return ImageType.IMAGE_3D; |
||||||
|
default: |
||||||
|
throw new com.jme3.opencl.OpenCLException("Unknown image type id: " + type); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getWidth() { |
||||||
|
return Info.clGetImageInfoPointer(image, CL10.CL_IMAGE_WIDTH); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getHeight() { |
||||||
|
return Info.clGetImageInfoPointer(image, CL10.CL_IMAGE_HEIGHT); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getDepth() { |
||||||
|
return Info.clGetImageInfoPointer(image, CL10.CL_IMAGE_DEPTH); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getRowPitch() { |
||||||
|
return Info.clGetImageInfoPointer(image, CL10.CL_IMAGE_ROW_PITCH); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getSlicePitch() { |
||||||
|
return Info.clGetImageInfoPointer(image, CL10.CL_IMAGE_SLICE_PITCH); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getArraySize() { |
||||||
|
return Info.clGetImageInfoPointer(image, CL12.CL_IMAGE_ARRAY_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageFormat getImageFormat() { |
||||||
|
Utils.b80.rewind(); |
||||||
|
CLImageFormat format = new CLImageFormat(Utils.b80); |
||||||
|
int ret = CL10.clGetImageInfo(image, CL10.CL_IMAGE_FORMAT, format.sizeof(), Utils.b80, null); |
||||||
|
Utils.checkError(ret, "clGetImageInfo"); |
||||||
|
return new ImageFormat(encodeImageChannelOrder(format.image_channel_order()), encodeImageChannelType(format.image_channel_data_type())); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageType getImageType() { |
||||||
|
int type = Info.clGetMemObjectInfoInt(image, CL10.CL_MEM_TYPE); |
||||||
|
return encodeImageType(type); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getElementSize() { |
||||||
|
return Info.clGetImageInfoInt(image, CL10.CL_IMAGE_ELEMENT_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void readImage(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueReadImage(q, image, CL10.CL_TRUE, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], |
||||||
|
rowPitch, slicePitch, dest, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueReadImage"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event readImageAsync(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueReadImage(q, image, CL10.CL_FALSE, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], |
||||||
|
rowPitch, slicePitch, dest, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueReadImage"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void writeImage(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueWriteImage(q, image, CL10.CL_TRUE, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], |
||||||
|
rowPitch, slicePitch, dest, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueWriteImage"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event writeImageAsync(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueWriteImage(q, image, CL10.CL_FALSE, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], |
||||||
|
rowPitch, slicePitch, dest, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueWriteImage"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void copyTo(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region) { |
||||||
|
if (srcOrigin.length!=3 || destOrigin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[3].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(srcOrigin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(destOrigin).position(0); |
||||||
|
Utils.pointerBuffers[3].put(region).position(0); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueCopyImage(q, image, ((LwjglImage) dest).getImage(), |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], Utils.pointerBuffers[3], |
||||||
|
null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyImage"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
ret = CL10.clWaitForEvents(event); |
||||||
|
Utils.checkError(ret, "clWaitForEvents"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event copyToAsync(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region) { |
||||||
|
if (srcOrigin.length!=3 || destOrigin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[3].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(srcOrigin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(destOrigin).position(0); |
||||||
|
Utils.pointerBuffers[3].put(region).position(0); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueCopyImage(q, image, ((LwjglImage) dest).getImage(), |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], Utils.pointerBuffers[3], |
||||||
|
null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyImage"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageMapping map(CommandQueue queue, long[] origin, long[] region, MappingAccess access) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[3].rewind(); |
||||||
|
Utils.pointerBuffers[4].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
long flags = Utils.getMappingAccessFlags(access); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
ByteBuffer buf = CL10.clEnqueueMapImage(q, image, CL10.CL_TRUE, flags, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], |
||||||
|
Utils.pointerBuffers[3], Utils.pointerBuffers[4], null, null, |
||||||
|
Utils.errorBuffer, null); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer"); |
||||||
|
return new ImageMapping(buf, Utils.pointerBuffers[3].get(0), Utils.pointerBuffers[4].get(0)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageMapping mapAsync(CommandQueue queue, long[] origin, long[] region, MappingAccess access) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[3].rewind(); |
||||||
|
Utils.pointerBuffers[4].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
long flags = Utils.getMappingAccessFlags(access); |
||||||
|
Utils.errorBuffer.rewind(); |
||||||
|
ByteBuffer buf = CL10.clEnqueueMapImage(q, image, CL10.CL_FALSE, flags, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], |
||||||
|
Utils.pointerBuffers[3], Utils.pointerBuffers[4], null, Utils.pointerBuffers[0], |
||||||
|
Utils.errorBuffer, null); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new ImageMapping(buf, Utils.pointerBuffers[3].get(0), Utils.pointerBuffers[4].get(0), new LwjglEvent(event)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void unmap(CommandQueue queue, ImageMapping mapping) { |
||||||
|
mapping.buffer.position(0); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
int ret = CL10.clEnqueueUnmapMemObject(q, image, mapping.buffer, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueUnmapMemObject"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
ret = CL10.clWaitForEvents(event); |
||||||
|
Utils.checkError(ret, "clWaitForEvents"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event fillAsync(CommandQueue queue, long[] origin, long[] region, ColorRGBA color) { |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
Utils.tempBuffers[0].b16f.rewind(); |
||||||
|
Utils.tempBuffers[0].b16f.limit(4); |
||||||
|
Utils.tempBuffers[0].b16f.put(color.r).put(color.g).put(color.b).put(color.a); |
||||||
|
Utils.tempBuffers[0].b16.rewind(); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL12.clEnqueueFillImage(q, image, Utils.tempBuffers[0].b16, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueFillImage"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(event); |
||||||
|
//TODO: why does q.getCLEvent(event) return null?
|
||||||
|
//This is a bug in LWJGL: they forgot to include the line
|
||||||
|
// if ( __result == CL_SUCCESS ) command_queue.registerCLEvent(event);
|
||||||
|
// after the native call
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event fillAsync(CommandQueue queue, long[] origin, long[] region, int[] color) { |
||||||
|
if (color.length != 4) { |
||||||
|
throw new IllegalArgumentException("the passed color array must have length 4"); |
||||||
|
} |
||||||
|
if (origin.length!=3 || region.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(origin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(region).position(0); |
||||||
|
Utils.tempBuffers[0].b16i.rewind(); |
||||||
|
Utils.tempBuffers[0].b16i.limit(4); |
||||||
|
Utils.tempBuffers[0].b16i.put(color); |
||||||
|
Utils.tempBuffers[0].b16.rewind(); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL12.clEnqueueFillImage(q, image, Utils.tempBuffers[0].b16, |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueFillImage"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event copyToBufferAsync(CommandQueue queue, Buffer dest, long[] srcOrigin, long[] srcRegion, long destOffset) { |
||||||
|
if (srcOrigin.length!=3 || srcRegion.length!=3) { |
||||||
|
throw new IllegalArgumentException("origin and region must both be arrays of length 3"); |
||||||
|
} |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[2].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(srcOrigin).position(0); |
||||||
|
Utils.pointerBuffers[2].put(srcRegion).position(0); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueCopyImageToBuffer(q, image, ((LwjglBuffer) dest).getBuffer(), |
||||||
|
Utils.pointerBuffers[1], Utils.pointerBuffers[2], destOffset, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueCopyImageToBuffer"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event acquireImageForSharingAsync(CommandQueue queue) { |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueAcquireGLObjects(q, image, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueAcquireGLObjects"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(event); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void acquireImageForSharingNoEvent(CommandQueue queue) { |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueAcquireGLObjects(q, image, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueAcquireGLObjects"); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public Event releaseImageForSharingAsync(CommandQueue queue) { |
||||||
|
Utils.assertSharingPossible(); |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueReleaseGLObjects(q, image, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueReleaseGLObjects"); |
||||||
|
long event = Utils.pointerBuffers[0].get(0); |
||||||
|
return new LwjglEvent(event); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void releaseImageForSharingNoEvent(CommandQueue queue) { |
||||||
|
Utils.assertSharingPossible(); |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10GL.clEnqueueReleaseGLObjects(q, image, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueReleaseGLObjects"); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private long mem; |
||||||
|
private ReleaserImpl(long mem) { |
||||||
|
this.mem = mem; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (mem != 0) { |
||||||
|
int ret = CL10.clReleaseMemObject(mem); |
||||||
|
mem = 0; |
||||||
|
Utils.reportError(ret, "clReleaseMemObject"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,233 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.math.Matrix4f; |
||||||
|
import com.jme3.math.Quaternion; |
||||||
|
import com.jme3.math.Vector2f; |
||||||
|
import com.jme3.math.Vector4f; |
||||||
|
import com.jme3.opencl.*; |
||||||
|
import com.jme3.opencl.Buffer; |
||||||
|
import java.nio.*; |
||||||
|
import org.lwjgl.PointerBuffer; |
||||||
|
import org.lwjgl.opencl.CL10; |
||||||
|
import org.lwjgl.opencl.CLDevice; |
||||||
|
import org.lwjgl.opencl.Info; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class LwjglKernel extends Kernel { |
||||||
|
|
||||||
|
private final long kernel; |
||||||
|
|
||||||
|
public LwjglKernel(long kernel) { |
||||||
|
super(new ReleaserImpl(kernel)); |
||||||
|
this.kernel = kernel; |
||||||
|
} |
||||||
|
|
||||||
|
public long getKernel() { |
||||||
|
return kernel; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return Info.clGetKernelInfoStringASCII(kernel, CL10.CL_KERNEL_FUNCTION_NAME); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getArgCount() { |
||||||
|
return Info.clGetKernelInfoInt(kernel, CL10.CL_KERNEL_NUM_ARGS); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getMaxWorkGroupSize(Device device) { |
||||||
|
long d = ((LwjglDevice) device).getDevice(); |
||||||
|
return Info.clGetKernelWorkGroupInfoPointer(kernel, d, CL10.CL_KERNEL_WORK_GROUP_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, LocalMemPerElement t) { |
||||||
|
int ret = CL10.clSetKernelArg (kernel, index, t.getSize() * workGroupSize.getSizes()[0] * workGroupSize.getSizes()[1] * workGroupSize.getSizes()[2]); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, LocalMem t) { |
||||||
|
int ret = CL10.clSetKernelArg (kernel, index, t.getSize()); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Buffer t) { |
||||||
|
int ret = CL10.clSetKernelArg1p(kernel, index, ((LwjglBuffer) t).getBuffer()); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Image i) { |
||||||
|
int ret = CL10.clSetKernelArg1p(kernel, index, ((LwjglImage) i).getImage()); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, byte b) { |
||||||
|
int ret = CL10.clSetKernelArg1b(kernel, index, b); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, short s) { |
||||||
|
int ret = CL10.clSetKernelArg1s(kernel, index, s); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, int i) { |
||||||
|
int ret = CL10.clSetKernelArg1i(kernel, index, i); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, long l) { |
||||||
|
int ret = CL10.clSetKernelArg1l(kernel, index, l); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, float f) { |
||||||
|
int ret = CL10.clSetKernelArg1f(kernel, index, f); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, double d) { |
||||||
|
int ret = CL10.clSetKernelArg1d(kernel, index, d); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Vector2f v) { |
||||||
|
int ret = CL10.clSetKernelArg2f(kernel, index, v.x, v.y); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Vector4f v) { |
||||||
|
int ret = CL10.clSetKernelArg4f(kernel, index, v.x, v.y, v.z, v.w); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Quaternion q) { |
||||||
|
int ret = CL10.clSetKernelArg4f(kernel, index, q.getX(), q.getY(), q.getZ(), q.getW()); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, Matrix4f m) { |
||||||
|
FloatBuffer buf = Utils.b80f; |
||||||
|
buf.position(0); |
||||||
|
buf.limit(16); |
||||||
|
buf.put(m.m00).put(m.m01).put(m.m02).put(m.m03); |
||||||
|
buf.put(m.m10).put(m.m11).put(m.m12).put(m.m13); |
||||||
|
buf.put(m.m20).put(m.m21).put(m.m22).put(m.m23); |
||||||
|
buf.put(m.m30).put(m.m31).put(m.m32).put(m.m33); |
||||||
|
buf.position(0); |
||||||
|
int ret = CL10.clSetKernelArg(kernel, index, buf); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setArg(int index, ByteBuffer buffer, long size) { |
||||||
|
buffer.limit((int) (buffer.position() + size)); |
||||||
|
int ret = CL10.clSetKernelArg(kernel, index, buffer); |
||||||
|
Utils.checkError(ret, "clSetKernelArg"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Event Run(CommandQueue queue) { |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(globalWorkSize.getSizes()); |
||||||
|
Utils.pointerBuffers[1].position(0); |
||||||
|
PointerBuffer p2 = null; |
||||||
|
if (workGroupSize.getSizes()[0] > 0) { |
||||||
|
p2 = Utils.pointerBuffers[2].rewind(); |
||||||
|
p2.put(workGroupSize.getSizes()); |
||||||
|
p2.position(0); |
||||||
|
} |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueNDRangeKernel(q, kernel, |
||||||
|
globalWorkSize.getDimension(), null, Utils.pointerBuffers[1], |
||||||
|
p2, null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clEnqueueNDRangeKernel"); |
||||||
|
return new LwjglEvent(Utils.pointerBuffers[0].get(0)); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void RunNoEvent(CommandQueue queue) { |
||||||
|
Utils.pointerBuffers[1].rewind(); |
||||||
|
Utils.pointerBuffers[1].put(globalWorkSize.getSizes()); |
||||||
|
Utils.pointerBuffers[1].position(0); |
||||||
|
PointerBuffer p2 = null; |
||||||
|
if (workGroupSize.getSizes()[0] > 0) { |
||||||
|
p2 = Utils.pointerBuffers[2].rewind(); |
||||||
|
p2.put(workGroupSize.getSizes()); |
||||||
|
p2.position(0); |
||||||
|
} |
||||||
|
long q = ((LwjglCommandQueue) queue).getQueue(); |
||||||
|
int ret = CL10.clEnqueueNDRangeKernel(q, kernel, |
||||||
|
globalWorkSize.getDimension(), null, Utils.pointerBuffers[1], |
||||||
|
p2, null, null); |
||||||
|
Utils.checkError(ret, "clEnqueueNDRangeKernel"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ObjectReleaser getReleaser() { |
||||||
|
return new ReleaserImpl(kernel); |
||||||
|
} |
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private long kernel; |
||||||
|
private ReleaserImpl(long kernel) { |
||||||
|
this.kernel = kernel; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (kernel != 0) { |
||||||
|
int ret = CL10.clReleaseKernel(kernel); |
||||||
|
kernel = 0; |
||||||
|
Utils.reportError(ret, "clReleaseKernel"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,128 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.Device; |
||||||
|
import com.jme3.opencl.Platform; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.List; |
||||||
|
import org.lwjgl.opencl.CL10; |
||||||
|
import org.lwjgl.opencl.CLDevice; |
||||||
|
import org.lwjgl.opencl.CLPlatform; |
||||||
|
import org.lwjgl.opencl.Info; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public final class LwjglPlatform implements Platform { |
||||||
|
|
||||||
|
final CLPlatform platform; |
||||||
|
List<LwjglDevice> devices; |
||||||
|
|
||||||
|
public LwjglPlatform(CLPlatform platform) { |
||||||
|
this.platform = platform; |
||||||
|
} |
||||||
|
|
||||||
|
public CLPlatform getPlatform() { |
||||||
|
return platform; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<LwjglDevice> getDevices() { |
||||||
|
if (devices == null) { |
||||||
|
devices = new ArrayList<>(); |
||||||
|
for (CLDevice d : platform.getDevices(CL10.CL_DEVICE_TYPE_ALL)) { |
||||||
|
devices.add(new LwjglDevice(d, this)); |
||||||
|
} |
||||||
|
} |
||||||
|
return devices; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getProfile() { |
||||||
|
return Info.clGetPlatformInfoStringASCII(platform.address(), CL10.CL_PLATFORM_PROFILE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isFullProfile() { |
||||||
|
return getProfile().contains("FULL_PROFILE"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isEmbeddedProfile() { |
||||||
|
return getProfile().contains("EMBEDDED_PROFILE"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getVersion() { |
||||||
|
return Info.clGetPlatformInfoStringASCII(platform.address(), CL10.CL_PLATFORM_VERSION); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getVersionMajor() { |
||||||
|
return Utils.getMajorVersion(getVersion(), "OpenCL "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getVersionMinor() { |
||||||
|
return Utils.getMinorVersion(getVersion(), "OpenCL "); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return Info.clGetPlatformInfoStringASCII(platform.address(), CL10.CL_PLATFORM_NAME); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getVendor() { |
||||||
|
return Info.clGetPlatformInfoStringASCII(platform.address(), CL10.CL_PLATFORM_VENDOR); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasExtension(String extension) { |
||||||
|
return getExtensions().contains(extension); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasOpenGLInterop() { |
||||||
|
return hasExtension("cl_khr_gl_sharing"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Collection<? extends String> getExtensions() { |
||||||
|
return Arrays.asList(Info.clGetPlatformInfoStringASCII(platform.address(), CL10.CL_PLATFORM_EXTENSIONS).split(" ")); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,189 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.*; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import org.lwjgl.BufferUtils; |
||||||
|
import org.lwjgl.PointerBuffer; |
||||||
|
import org.lwjgl.opencl.*; |
||||||
|
import org.lwjgl.system.MemoryUtil; |
||||||
|
import org.lwjgl.system.Pointer; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class LwjglProgram extends Program { |
||||||
|
private static final Logger LOG = Logger.getLogger(LwjglProgram.class.getName()); |
||||||
|
|
||||||
|
private final long program; |
||||||
|
private final LwjglContext context; |
||||||
|
|
||||||
|
public LwjglProgram(long program, LwjglContext context) { |
||||||
|
super(new ReleaserImpl(program)); |
||||||
|
this.program = program; |
||||||
|
this.context = context; |
||||||
|
} |
||||||
|
|
||||||
|
public long getProgram() { |
||||||
|
return program; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void build(String args, Device... devices) throws KernelCompilationException { |
||||||
|
PointerBuffer deviceList = null; |
||||||
|
if (devices != null) { |
||||||
|
deviceList = PointerBuffer.allocateDirect(devices.length); |
||||||
|
deviceList.rewind(); |
||||||
|
for (Device d : devices) { |
||||||
|
deviceList.put(((LwjglDevice) d).getDevice()); |
||||||
|
} |
||||||
|
deviceList.flip(); |
||||||
|
} |
||||||
|
int ret = CL10.clBuildProgram(program, deviceList, args, null, 0); |
||||||
|
if (ret != CL10.CL_SUCCESS) { |
||||||
|
String log = Log(); |
||||||
|
LOG.log(Level.WARNING, "Unable to compile program:\n{0}", log); |
||||||
|
if (ret == CL10.CL_BUILD_PROGRAM_FAILURE) { |
||||||
|
throw new KernelCompilationException("Failed to build program", ret, log); |
||||||
|
} else { |
||||||
|
Utils.checkError(ret, "clBuildProgram"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
LOG.log(Level.INFO, "Program compiled:\n{0}", Log()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private String Log(long device) { |
||||||
|
Utils.pointerBuffers[0].rewind(); |
||||||
|
int ret = CL10.clGetProgramBuildInfo(program, device, CL10.CL_PROGRAM_BUILD_LOG, (ByteBuffer) null, Utils.pointerBuffers[0]); |
||||||
|
Utils.checkError(ret, "clGetProgramBuildInfo"); |
||||||
|
int count = (int) Utils.pointerBuffers[0].get(0); |
||||||
|
final ByteBuffer buffer = BufferUtils.createByteBuffer(count); |
||||||
|
ret = CL10.clGetProgramBuildInfo(program, device, CL10.CL_PROGRAM_BUILD_LOG, buffer, null); |
||||||
|
Utils.checkError(ret, "clGetProgramBuildInfo"); |
||||||
|
return MemoryUtil.memDecodeASCII(buffer); |
||||||
|
} |
||||||
|
|
||||||
|
private String Log() { |
||||||
|
StringBuilder str = new StringBuilder(); |
||||||
|
for (LwjglDevice device : context.getDevices()) { |
||||||
|
long d = device.getDevice(); |
||||||
|
str.append(device.getName()).append(":\n"); |
||||||
|
//str.append(Info.clGetProgramBuildInfoStringASCII(program, d, CL10.CL_PROGRAM_BUILD_LOG)); //This throws an IllegalArgumentException in Buffer.limit()
|
||||||
|
str.append(Log(d)); |
||||||
|
str.append('\n'); |
||||||
|
} |
||||||
|
return str.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Kernel createKernel(String name) { |
||||||
|
long kernel = CL10.clCreateKernel(program, name, Utils.errorBuffer); |
||||||
|
Utils.checkError(Utils.errorBuffer, "clCreateKernel"); |
||||||
|
return new LwjglKernel(kernel); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Kernel[] createAllKernels() { |
||||||
|
Utils.tempBuffers[0].b16i.rewind(); |
||||||
|
int ret = CL10.clCreateKernelsInProgram(program, null, Utils.tempBuffers[0].b16i); |
||||||
|
Utils.checkError(ret, "clCreateKernelsInProgram"); |
||||||
|
int count = Utils.tempBuffers[0].b16i.get(0); |
||||||
|
PointerBuffer buf = PointerBuffer.allocateDirect(count); |
||||||
|
ret = CL10.clCreateKernelsInProgram(program, buf, null); |
||||||
|
Utils.checkError(ret, "clCreateKernelsInProgram"); |
||||||
|
Kernel[] kx = new Kernel[count]; |
||||||
|
for (int i=0; i<count; ++i) { |
||||||
|
kx[i] = new LwjglKernel(buf.get()); |
||||||
|
} |
||||||
|
return kx; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ByteBuffer getBinary(Device d) { |
||||||
|
//throw new UnsupportedOperationException("Not supported yet, would crash the JVM");
|
||||||
|
|
||||||
|
LwjglDevice device = (LwjglDevice) d; |
||||||
|
int numDevices = Info.clGetProgramInfoInt(program, CL10.CL_PROGRAM_NUM_DEVICES); |
||||||
|
|
||||||
|
PointerBuffer devices = PointerBuffer.allocateDirect(numDevices); |
||||||
|
int ret = CL10.clGetProgramInfo(program, CL10.CL_PROGRAM_DEVICES, devices, null); |
||||||
|
Utils.checkError(ret, "clGetProgramInfo: CL_PROGRAM_DEVICES"); |
||||||
|
int index = -1; |
||||||
|
for (int i=0; i<numDevices; ++i) { |
||||||
|
if (devices.get(i) == device.getDevice()) { |
||||||
|
index = i; |
||||||
|
} |
||||||
|
} |
||||||
|
if (index == -1) { |
||||||
|
throw new com.jme3.opencl.OpenCLException("Program was not built against the specified device "+device); |
||||||
|
} |
||||||
|
|
||||||
|
PointerBuffer sizes = PointerBuffer.allocateDirect(numDevices); |
||||||
|
ret = CL10.clGetProgramInfo(program, CL10.CL_PROGRAM_BINARY_SIZES, sizes, null); |
||||||
|
Utils.checkError(ret, "clGetProgramInfo: CL_PROGRAM_BINARY_SIZES"); |
||||||
|
int size = (int) sizes.get(index); |
||||||
|
|
||||||
|
PointerBuffer binaryPointers = PointerBuffer.allocateDirect(numDevices); |
||||||
|
for (int i=0; i<binaryPointers.capacity(); ++i) { |
||||||
|
binaryPointers.put(0L); |
||||||
|
} |
||||||
|
binaryPointers.rewind(); |
||||||
|
ByteBuffer binaries = ByteBuffer.allocateDirect(size); |
||||||
|
binaryPointers.put(index, binaries); |
||||||
|
|
||||||
|
//Fixme: why the hell does this line throw a segfault ?!?
|
||||||
|
ret = CL10.clGetProgramInfo(program, CL10.CL_PROGRAM_BINARIES, binaryPointers, null); |
||||||
|
Utils.checkError(ret, "clGetProgramInfo: CL_PROGRAM_BINARIES"); |
||||||
|
|
||||||
|
return binaries; |
||||||
|
} |
||||||
|
|
||||||
|
private static class ReleaserImpl implements ObjectReleaser { |
||||||
|
private long program; |
||||||
|
private ReleaserImpl(long program) { |
||||||
|
this.program = program; |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void release() { |
||||||
|
if (program != 0) { |
||||||
|
int ret = CL10.clReleaseProgram(program); |
||||||
|
program = 0; |
||||||
|
Utils.reportError(ret, "clReleaseProgram"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,163 @@ |
|||||||
|
/* |
||||||
|
* 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.lwjgl; |
||||||
|
|
||||||
|
import com.jme3.opencl.MappingAccess; |
||||||
|
import com.jme3.opencl.MemoryAccess; |
||||||
|
import com.jme3.opencl.OpenCLException; |
||||||
|
import java.nio.*; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import org.lwjgl.BufferUtils; |
||||||
|
import org.lwjgl.PointerBuffer; |
||||||
|
import org.lwjgl.opencl.*; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author shaman |
||||||
|
*/ |
||||||
|
public class Utils { |
||||||
|
private static final Logger LOG = Logger.getLogger(Utils.class.getName()); |
||||||
|
private Utils() {} |
||||||
|
|
||||||
|
public static final boolean CL_GL_SHARING_POSSIBLE = com.jme3.system.lwjgl.LwjglContext.CL_GL_SHARING_POSSIBLE; |
||||||
|
public static void assertSharingPossible() { |
||||||
|
if (!CL_GL_SHARING_POSSIBLE) { |
||||||
|
throw new OpenCLException("OpenGL/CL sharing not possible"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static int getMajorVersion(String version, String prefix) { |
||||||
|
String s = version.substring(prefix.length()); |
||||||
|
return Integer.parseInt(s); |
||||||
|
} |
||||||
|
|
||||||
|
public static int getMinorVersion(String version, String prefix) { |
||||||
|
String s = version.substring(prefix.length()); |
||||||
|
int major = Integer.parseInt(s); |
||||||
|
s = s.substring((int) (Math.log10(major) + 2)); |
||||||
|
return Integer.parseInt(s); |
||||||
|
} |
||||||
|
|
||||||
|
public static final class TempBuffer { |
||||||
|
public final ByteBuffer b16; |
||||||
|
public final ShortBuffer b16s; |
||||||
|
public final IntBuffer b16i; |
||||||
|
public final LongBuffer b16l; |
||||||
|
public final FloatBuffer b16f; |
||||||
|
public final DoubleBuffer b16d; |
||||||
|
public TempBuffer() { |
||||||
|
b16 = BufferUtils.createByteBuffer(16); |
||||||
|
b16s = b16.asShortBuffer(); |
||||||
|
b16i = b16.asIntBuffer(); |
||||||
|
b16l = b16.asLongBuffer(); |
||||||
|
b16f = b16.asFloatBuffer(); |
||||||
|
b16d = b16.asDoubleBuffer(); |
||||||
|
} |
||||||
|
} |
||||||
|
public static final ByteBuffer b80; //needed for ImageDescriptor
|
||||||
|
public static final LongBuffer b80l; |
||||||
|
public static final FloatBuffer b80f; |
||||||
|
public static final TempBuffer[] tempBuffers = new TempBuffer[8]; |
||||||
|
public static final PointerBuffer[] pointerBuffers = new PointerBuffer[8]; |
||||||
|
static { |
||||||
|
for (int i=0; i<8; ++i) { |
||||||
|
tempBuffers[i] = new TempBuffer(); |
||||||
|
pointerBuffers[i] = PointerBuffer.allocateDirect(4); |
||||||
|
} |
||||||
|
errorBuffer = BufferUtils.createIntBuffer(1); |
||||||
|
b80 = BufferUtils.createByteBuffer(80); |
||||||
|
b80l = b80.asLongBuffer(); |
||||||
|
b80f = b80.asFloatBuffer(); |
||||||
|
} |
||||||
|
|
||||||
|
public static IntBuffer errorBuffer; |
||||||
|
public static void checkError(IntBuffer errorBuffer, String callName) { |
||||||
|
checkError(errorBuffer.get(0), callName); |
||||||
|
} |
||||||
|
public static void checkError(int error, String callName) { |
||||||
|
if (error != CL10.CL_SUCCESS) { |
||||||
|
String errname = getErrorName(error); |
||||||
|
if (errname == null) { |
||||||
|
errname = "UNKNOWN"; |
||||||
|
} |
||||||
|
throw new OpenCLException("OpenCL error in " + callName + ": " + errname + " (0x" + Integer.toHexString(error) + ")", error); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void reportError(int error, String callName) { |
||||||
|
if (error != CL10.CL_SUCCESS) { |
||||||
|
String errname = getErrorName(error); |
||||||
|
if (errname == null) { |
||||||
|
errname = "UNKNOWN"; |
||||||
|
} |
||||||
|
LOG.log(Level.WARNING, "OpenCL error in {0}: {1} (0x{2})", new Object[]{callName, errname, Integer.toHexString(error)}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static String getErrorName(int code) { |
||||||
|
return CLUtil.getErrcodeName(code); |
||||||
|
} |
||||||
|
|
||||||
|
public static long getMemoryAccessFlags(MemoryAccess ma) { |
||||||
|
switch (ma) { |
||||||
|
case READ_ONLY: return CL10.CL_MEM_READ_ONLY; |
||||||
|
case WRITE_ONLY: return CL10.CL_MEM_WRITE_ONLY; |
||||||
|
case READ_WRITE: return CL10.CL_MEM_READ_WRITE; |
||||||
|
default: throw new IllegalArgumentException("Unknown memory access: "+ma); |
||||||
|
} |
||||||
|
} |
||||||
|
public static MemoryAccess getMemoryAccessFromFlag(long flag) { |
||||||
|
if ((flag & CL10.CL_MEM_READ_WRITE) > 0) { |
||||||
|
return MemoryAccess.READ_WRITE; |
||||||
|
} |
||||||
|
if ((flag & CL10.CL_MEM_READ_ONLY) > 0) { |
||||||
|
return MemoryAccess.READ_ONLY; |
||||||
|
} |
||||||
|
if ((flag & CL10.CL_MEM_WRITE_ONLY) > 0) { |
||||||
|
return MemoryAccess.WRITE_ONLY; |
||||||
|
} |
||||||
|
throw new OpenCLException("Unknown memory access flag: "+flag); |
||||||
|
} |
||||||
|
|
||||||
|
public static long getMappingAccessFlags(MappingAccess ma) { |
||||||
|
switch (ma) { |
||||||
|
case MAP_READ_ONLY: return CL10.CL_MAP_READ; |
||||||
|
case MAP_READ_WRITE: return CL10.CL_MAP_READ | CL10.CL_MAP_WRITE; |
||||||
|
case MAP_WRITE_ONLY: return CL10.CL_MAP_WRITE; |
||||||
|
case MAP_WRITE_INVALIDATE: return CL12.CL_MAP_WRITE_INVALIDATE_REGION; |
||||||
|
default: throw new IllegalArgumentException("Unknown mapping access: "+ma); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue