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