commit
fbf2dd4497
@ -457,4 +457,10 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.jme3.opencl.Context getOpenCLContext() {
|
||||
logger.warning("OpenCL is not yet supported on android");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
427
jme3-core/src/main/java/com/jme3/opencl/Buffer.java
Normal file
427
jme3-core/src/main/java/com/jme3/opencl/Buffer.java
Normal file
@ -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();
|
||||
}
|
||||
|
||||
}
|
68
jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java
Normal file
68
jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java
Normal file
@ -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();
|
||||
|
||||
}
|
439
jme3-core/src/main/java/com/jme3/opencl/Context.java
Normal file
439
jme3-core/src/main/java/com/jme3/opencl/Context.java
Normal file
@ -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
|
||||
}
|
||||
|
||||
}
|
311
jme3-core/src/main/java/com/jme3/opencl/Device.java
Normal file
311
jme3-core/src/main/java/com/jme3/opencl/Device.java
Normal file
@ -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();
|
||||
|
||||
}
|
59
jme3-core/src/main/java/com/jme3/opencl/Event.java
Normal file
59
jme3-core/src/main/java/com/jme3/opencl/Event.java
Normal file
@ -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();
|
||||
}
|
537
jme3-core/src/main/java/com/jme3/opencl/Image.java
Normal file
537
jme3-core/src/main/java/com/jme3/opencl/Image.java
Normal file
@ -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
|
||||
}
|
628
jme3-core/src/main/java/com/jme3/opencl/Kernel.java
Normal file
628
jme3-core/src/main/java/com/jme3/opencl/Kernel.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
58
jme3-core/src/main/java/com/jme3/opencl/MappingAccess.java
Normal file
58
jme3-core/src/main/java/com/jme3/opencl/MappingAccess.java
Normal file
@ -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
|
||||
}
|
52
jme3-core/src/main/java/com/jme3/opencl/MemoryAccess.java
Normal file
52
jme3-core/src/main/java/com/jme3/opencl/MemoryAccess.java
Normal file
@ -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
|
||||
}
|
78
jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java
Normal file
78
jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
75
jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java
Normal file
75
jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java
Normal file
@ -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();
|
||||
}
|
123
jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java
Normal file
123
jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
107
jme3-core/src/main/java/com/jme3/opencl/Platform.java
Normal file
107
jme3-core/src/main/java/com/jme3/opencl/Platform.java
Normal file
@ -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();
|
||||
|
||||
}
|
54
jme3-core/src/main/java/com/jme3/opencl/PlatformChooser.java
Normal file
54
jme3-core/src/main/java/com/jme3/opencl/PlatformChooser.java
Normal file
@ -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);
|
||||
|
||||
}
|
104
jme3-core/src/main/java/com/jme3/opencl/Program.java
Normal file
104
jme3-core/src/main/java/com/jme3/opencl/Program.java
Normal file
@ -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);
|
||||
|
||||
}
|
229
jme3-core/src/main/java/com/jme3/opencl/ProgramCache.java
Normal file
229
jme3-core/src/main/java/com/jme3/opencl/ProgramCache.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
163
jme3-core/src/main/java/com/jme3/opencl/package-info.java
Normal file
163
jme3-core/src/main/java/com/jme3/opencl/package-info.java
Normal file
@ -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
|
@ -35,6 +35,7 @@ import com.jme3.material.RenderState;
|
||||
import com.jme3.material.RenderState.StencilOperation;
|
||||
import com.jme3.material.RenderState.TestFunction;
|
||||
import com.jme3.math.*;
|
||||
import com.jme3.opencl.OpenCLObjectManager;
|
||||
import com.jme3.renderer.*;
|
||||
import com.jme3.scene.Mesh;
|
||||
import com.jme3.scene.Mesh.Mode;
|
||||
@ -552,6 +553,7 @@ public final class GLRenderer implements Renderer {
|
||||
public void cleanup() {
|
||||
logger.log(Level.FINE, "Deleting objects and invalidating state");
|
||||
objManager.deleteAllObjects(this);
|
||||
OpenCLObjectManager.getInstance().deleteAllObjects();
|
||||
statistics.clearMemory();
|
||||
invalidateState();
|
||||
}
|
||||
@ -935,6 +937,7 @@ public final class GLRenderer implements Renderer {
|
||||
|
||||
public void postFrame() {
|
||||
objManager.deleteUnused(this);
|
||||
OpenCLObjectManager.getInstance().deleteUnusedObjects();
|
||||
gl.resetStats();
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,8 @@
|
||||
*/
|
||||
package com.jme3.system;
|
||||
|
||||
import com.jme3.opencl.DefaultPlatformChooser;
|
||||
import com.jme3.opencl.PlatformChooser;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@ -160,7 +162,9 @@ public final class AppSettings extends HashMap<String, Object> {
|
||||
defaults.put("GammaCorrection", false);
|
||||
defaults.put("Resizable", false);
|
||||
defaults.put("SwapBuffers", true);
|
||||
// defaults.put("Icons", null);
|
||||
defaults.put("OpenCL", false);
|
||||
defaults.put("OpenCLPlatformChooser", DefaultPlatformChooser.class.getName());
|
||||
// defaults.put("Icons", null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1019,4 +1023,33 @@ public final class AppSettings extends HashMap<String, Object> {
|
||||
public boolean isSwapBuffers() {
|
||||
return getBoolean("SwapBuffers");
|
||||
}
|
||||
|
||||
/**
|
||||
* True to enable the creation of an OpenCL context.
|
||||
*
|
||||
* @param support
|
||||
*/
|
||||
public void setOpenCLSupport(boolean support) {
|
||||
putBoolean("OpenCL", support);
|
||||
}
|
||||
|
||||
public boolean isOpenCLSupport() {
|
||||
return getBoolean("OpenCL");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom platform chooser. This chooser specifies which platform and
|
||||
* which devices are used for the OpenCL context.
|
||||
*
|
||||
* Default: an implementation defined one.
|
||||
*
|
||||
* @param chooser the class of the chooser, must have a default constructor
|
||||
*/
|
||||
public void setOpenCLPlatformChooser(Class<? extends PlatformChooser> chooser) {
|
||||
putString("OpenCLPlatformChooser", chooser.getName());
|
||||
}
|
||||
|
||||
public String getOpenCLPlatformChooser() {
|
||||
return getString("OpenCLPlatformChooser");
|
||||
}
|
||||
}
|
||||
|
@ -110,6 +110,11 @@ public interface JmeContext {
|
||||
*/
|
||||
public Renderer getRenderer();
|
||||
|
||||
/**
|
||||
* @return The OpenCL context if available.
|
||||
*/
|
||||
public com.jme3.opencl.Context getOpenCLContext();
|
||||
|
||||
/**
|
||||
* @return Mouse input implementation. May be null if not available.
|
||||
*/
|
||||
|
@ -37,6 +37,7 @@ import com.jme3.input.MouseInput;
|
||||
import com.jme3.input.TouchInput;
|
||||
import com.jme3.input.dummy.DummyKeyInput;
|
||||
import com.jme3.input.dummy.DummyMouseInput;
|
||||
import com.jme3.opencl.Context;
|
||||
import com.jme3.renderer.Renderer;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
@ -229,4 +230,9 @@ public class NullContext implements JmeContext, Runnable {
|
||||
return true; // Doesn't really matter if true or false. Either way
|
||||
// RenderManager won't render anything.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getOpenCLContext() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
224
jme3-core/src/main/resources/Common/OpenCL/Matrix3f.clh
Normal file
224
jme3-core/src/main/resources/Common/OpenCL/Matrix3f.clh
Normal file
@ -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
|
319
jme3-core/src/main/resources/Common/OpenCL/Matrix4f.clh
Normal file
319
jme3-core/src/main/resources/Common/OpenCL/Matrix4f.clh
Normal file
@ -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
|
185
jme3-core/src/main/resources/Common/OpenCL/Random.clh
Normal file
185
jme3-core/src/main/resources/Common/OpenCL/Random.clh
Normal file
@ -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
|
@ -37,6 +37,7 @@ import com.jme3.input.MouseInput;
|
||||
import com.jme3.input.TouchInput;
|
||||
import com.jme3.input.awt.AwtKeyInput;
|
||||
import com.jme3.input.awt.AwtMouseInput;
|
||||
import com.jme3.opencl.Context;
|
||||
import com.jme3.renderer.Renderer;
|
||||
import com.jme3.system.*;
|
||||
import java.util.ArrayList;
|
||||
@ -145,6 +146,11 @@ public class AwtPanelsContext implements JmeContext {
|
||||
return actualContext != null && actualContext.isRenderable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getOpenCLContext() {
|
||||
return actualContext.getOpenCLContext();
|
||||
}
|
||||
|
||||
public AwtPanelsContext(){
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ dependencies {
|
||||
compile project(':jme3-jogg')
|
||||
compile project(':jme3-jogl')
|
||||
compile project(':jme3-lwjgl')
|
||||
// compile project(':jme3-lwjgl3')
|
||||
compile project(':jme3-networking')
|
||||
compile project(':jme3-niftygui')
|
||||
compile project(':jme3-plugins')
|
||||
|
311
jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java
Normal file
311
jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
4
jme3-examples/src/main/resources/jme3test/opencl/Blas.cl
Normal file
4
jme3-examples/src/main/resources/jme3test/opencl/Blas.cl
Normal file
@ -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>
|
99
jme3-examples/src/main/resources/jme3test/opencl/JuliaSet.cl
Normal file
99
jme3-examples/src/main/resources/jme3test/opencl/JuliaSet.cl
Normal file
@ -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);
|
||||
}
|
@ -36,6 +36,7 @@ import com.jme3.input.dummy.DummyKeyInput;
|
||||
import com.jme3.input.dummy.DummyMouseInput;
|
||||
import com.jme3.system.*;
|
||||
import com.jme3.input.ios.IosInputHandler;
|
||||
import com.jme3.opencl.Context;
|
||||
import com.jme3.renderer.ios.IosGL;
|
||||
import com.jme3.renderer.opengl.GL;
|
||||
import com.jme3.renderer.opengl.GLDebugES;
|
||||
@ -212,4 +213,10 @@ public class IGLESContext implements JmeContext {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getOpenCLContext() {
|
||||
logger.warning("OpenCL not yet supported on this platform");
|
||||
return null;
|
||||
}
|
||||
}
|
@ -8,4 +8,5 @@ dependencies {
|
||||
compile 'org.jogamp.gluegen:gluegen-rt-main:2.3.2'
|
||||
compile 'org.jogamp.jogl:jogl-all-main:2.3.2'
|
||||
compile 'org.jogamp.joal:joal-main:2.3.2'
|
||||
compile 'org.jogamp.jocl:jocl-main:2.3.2'
|
||||
}
|
||||
|
236
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java
Normal file
236
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
262
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java
Normal file
262
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
302
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclDevice.java
Normal file
302
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclDevice.java
Normal file
@ -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();
|
||||
}
|
||||
|
||||
}
|
100
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclEvent.java
Normal file
100
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclEvent.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
544
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java
Normal file
544
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
290
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java
Normal file
290
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
127
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclPlatform.java
Normal file
127
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclPlatform.java
Normal file
@ -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();
|
||||
}
|
||||
|
||||
}
|
194
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java
Normal file
194
jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
162
jme3-jogl/src/main/java/com/jme3/opencl/jocl/Utils.java
Normal file
162
jme3-jogl/src/main/java/com/jme3/opencl/jocl/Utils.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -35,6 +35,12 @@ package com.jme3.system.jogl;
|
||||
import com.jme3.input.JoyInput;
|
||||
import com.jme3.input.KeyInput;
|
||||
import com.jme3.input.MouseInput;
|
||||
import com.jme3.opencl.Context;
|
||||
import com.jme3.opencl.DefaultPlatformChooser;
|
||||
import com.jme3.opencl.Device;
|
||||
import com.jme3.opencl.PlatformChooser;
|
||||
import com.jme3.opencl.jocl.JoclDevice;
|
||||
import com.jme3.opencl.jocl.JoclPlatform;
|
||||
import com.jme3.renderer.Renderer;
|
||||
import com.jme3.renderer.RendererException;
|
||||
import com.jme3.renderer.jogl.JoglGL;
|
||||
@ -55,6 +61,10 @@ import com.jme3.system.JmeContext;
|
||||
import com.jme3.system.NanoTimer;
|
||||
import com.jme3.system.SystemListener;
|
||||
import com.jme3.system.Timer;
|
||||
import com.jogamp.opencl.CLDevice;
|
||||
import com.jogamp.opencl.CLPlatform;
|
||||
import com.jogamp.opencl.gl.CLGLContext;
|
||||
import com.jogamp.opencl.llb.CL;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@ -64,6 +74,8 @@ import java.util.logging.Logger;
|
||||
import com.jogamp.opengl.GL;
|
||||
import com.jogamp.opengl.GL2GL3;
|
||||
import com.jogamp.opengl.GLContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class JoglContext implements JmeContext {
|
||||
|
||||
@ -84,6 +96,8 @@ public abstract class JoglContext implements JmeContext {
|
||||
protected MouseInput mouseInput;
|
||||
protected JoyInput joyInput;
|
||||
|
||||
protected com.jme3.opencl.Context clContext;
|
||||
|
||||
@Override
|
||||
public void setSystemListener(SystemListener listener){
|
||||
this.listener = listener;
|
||||
@ -209,6 +223,101 @@ public abstract class JoglContext implements JmeContext {
|
||||
if (joyInput != null) {
|
||||
joyInput.initialize();
|
||||
}
|
||||
|
||||
if (settings.isOpenCLSupport()) {
|
||||
initOpenCL();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void initOpenCL() {
|
||||
logger.info("Initialize OpenCL with JOGL");
|
||||
|
||||
//load platforms and devices
|
||||
StringBuilder platformInfos = new StringBuilder();
|
||||
ArrayList<JoclPlatform> platforms = new ArrayList<JoclPlatform>();
|
||||
for (CLPlatform p : CLPlatform.listCLPlatforms()) {
|
||||
platforms.add(new JoclPlatform(p));
|
||||
}
|
||||
platformInfos.append("Available OpenCL platforms:");
|
||||
for (int i=0; i<platforms.size(); ++i) {
|
||||
JoclPlatform platform = platforms.get(i);
|
||||
platformInfos.append("\n * Platform ").append(i+1);
|
||||
platformInfos.append("\n * Name: ").append(platform.getName());
|
||||
platformInfos.append("\n * Vendor: ").append(platform.getVendor());
|
||||
platformInfos.append("\n * Version: ").append(platform.getVersion());
|
||||
platformInfos.append("\n * Profile: ").append(platform.getProfile());
|
||||
platformInfos.append("\n * Supports interop: ").append(platform.hasOpenGLInterop());
|
||||
List<JoclDevice> devices = platform.getDevices();
|
||||
platformInfos.append("\n * Available devices:");
|
||||
for (int j=0; j<devices.size(); ++j) {
|
||||
JoclDevice device = devices.get(j);
|
||||
platformInfos.append("\n * * Device ").append(j+1);
|
||||
platformInfos.append("\n * * Name: ").append(device.getName());
|
||||
platformInfos.append("\n * * Vendor: ").append(device.getVendor());
|
||||
platformInfos.append("\n * * Version: ").append(device.getVersion());
|
||||
platformInfos.append("\n * * Profile: ").append(device.getProfile());
|
||||
platformInfos.append("\n * * Compiler version: ").append(device.getCompilerVersion());
|
||||
platformInfos.append("\n * * Device type: ").append(device.getDeviceType());
|
||||
platformInfos.append("\n * * Compute units: ").append(device.getComputeUnits());
|
||||
platformInfos.append("\n * * Work group size: ").append(device.getMaxiumWorkItemsPerGroup());
|
||||
platformInfos.append("\n * * Global memory: ").append(device.getGlobalMemorySize()).append("B");
|
||||
platformInfos.append("\n * * Local memory: ").append(device.getLocalMemorySize()).append("B");
|
||||
platformInfos.append("\n * * Constant memory: ").append(device.getMaximumConstantBufferSize()).append("B");
|
||||
platformInfos.append("\n * * Supports double: ").append(device.hasDouble());
|
||||
platformInfos.append("\n * * Supports half floats: ").append(device.hasHalfFloat());
|
||||
platformInfos.append("\n * * Supports writable 3d images: ").append(device.hasWritableImage3D());
|
||||
platformInfos.append("\n * * Supports interop: ").append(device.hasOpenGLInterop());
|
||||
}
|
||||
}
|
||||
logger.info(platformInfos.toString());
|
||||
|
||||
//choose devices
|
||||
PlatformChooser chooser = null;
|
||||
if (settings.getOpenCLPlatformChooser() != null) {
|
||||
try {
|
||||
chooser = (PlatformChooser) Class.forName(settings.getOpenCLPlatformChooser()).newInstance();
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.WARNING, "unable to instantiate custom PlatformChooser", ex);
|
||||
}
|
||||
}
|
||||
if (chooser == null) {
|
||||
chooser = new DefaultPlatformChooser();
|
||||
}
|
||||
List<? extends Device> choosenDevices = chooser.chooseDevices(platforms);
|
||||
List<CLDevice> devices = new ArrayList<>(choosenDevices.size());
|
||||
JoclPlatform platform = null;
|
||||
for (Device d : choosenDevices) {
|
||||
if (!(d instanceof JoclDevice)) {
|
||||
logger.log(Level.SEVERE, "attempt to return a custom Device implementation from PlatformChooser: {0}", d);
|
||||
return;
|
||||
}
|
||||
JoclDevice ld = (JoclDevice) d;
|
||||
if (platform == null) {
|
||||
platform = ld.getPlatform();
|
||||
} else if (platform != ld.getPlatform()) {
|
||||
logger.severe("attempt to use devices from different platforms");
|
||||
return;
|
||||
}
|
||||
devices.add(ld.getDevice());
|
||||
}
|
||||
if (devices.isEmpty()) {
|
||||
logger.warning("no devices specified, no OpenCL context created");
|
||||
return;
|
||||
}
|
||||
logger.log(Level.INFO, "chosen platform: {0}", platform.getName());
|
||||
logger.log(Level.INFO, "chosen devices: {0}", choosenDevices);
|
||||
|
||||
//create context
|
||||
try {
|
||||
CLGLContext c = CLGLContext.create(GLContext.getCurrent(), devices.toArray(new CLDevice[devices.size()]));
|
||||
clContext = new com.jme3.opencl.jocl.JoclContext(c, (List<JoclDevice>) choosenDevices);
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "Unable to create OpenCL context", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("OpenCL context created");
|
||||
}
|
||||
|
||||
public void internalCreate() {
|
||||
@ -266,4 +375,10 @@ public abstract class JoglContext implements JmeContext {
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getOpenCLContext() {
|
||||
return clContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
236
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java
Normal file
236
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
240
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java
Normal file
240
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
293
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java
Normal file
293
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java
Normal file
@ -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();
|
||||
}
|
||||
|
||||
}
|
100
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java
Normal file
100
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
575
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java
Normal file
575
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
277
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java
Normal file
277
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java
Normal file
@ -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(" "));
|
||||
}
|
||||
|
||||
}
|
145
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java
Normal file
145
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java
Normal file
@ -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");
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
167
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java
Normal file
167
jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -35,6 +35,11 @@ package com.jme3.system.lwjgl;
|
||||
import com.jme3.input.lwjgl.JInputJoyInput;
|
||||
import com.jme3.input.lwjgl.LwjglKeyInput;
|
||||
import com.jme3.input.lwjgl.LwjglMouseInput;
|
||||
import com.jme3.opencl.Device;
|
||||
import com.jme3.opencl.PlatformChooser;
|
||||
import com.jme3.opencl.lwjgl.LwjglDevice;
|
||||
import com.jme3.opencl.lwjgl.LwjglPlatform;
|
||||
import com.jme3.opencl.DefaultPlatformChooser;
|
||||
import com.jme3.renderer.Renderer;
|
||||
import com.jme3.renderer.RendererException;
|
||||
import com.jme3.renderer.lwjgl.LwjglGL;
|
||||
@ -54,12 +59,15 @@ import com.jme3.renderer.opengl.GLTimingState;
|
||||
import com.jme3.renderer.opengl.GLTracer;
|
||||
import com.jme3.system.*;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.Sys;
|
||||
import org.lwjgl.opencl.*;
|
||||
import org.lwjgl.opengl.*;
|
||||
|
||||
/**
|
||||
@ -81,6 +89,9 @@ public abstract class LwjglContext implements JmeContext {
|
||||
protected JInputJoyInput joyInput;
|
||||
protected Timer timer;
|
||||
protected SystemListener listener;
|
||||
|
||||
protected LwjglPlatform clPlatform;
|
||||
protected com.jme3.opencl.lwjgl.LwjglContext clContext;
|
||||
|
||||
public void setSystemListener(SystemListener listener) {
|
||||
this.listener = listener;
|
||||
@ -245,8 +256,108 @@ public abstract class LwjglContext implements JmeContext {
|
||||
if (joyInput != null) {
|
||||
joyInput.initialize();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void initOpenCL() {
|
||||
logger.info("Initialize OpenCL wiht LWJGL2");
|
||||
|
||||
try {
|
||||
CL.create();
|
||||
} catch (LWJGLException ex) {
|
||||
logger.log(Level.SEVERE, "Unable to initialize OpenCL", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
//load platforms and devices
|
||||
StringBuilder platformInfos = new StringBuilder();
|
||||
ArrayList<LwjglPlatform> platforms = new ArrayList<>();
|
||||
for (CLPlatform p : CLPlatform.getPlatforms()) {
|
||||
platforms.add(new LwjglPlatform(p));
|
||||
}
|
||||
platformInfos.append("Available OpenCL platforms:");
|
||||
for (int i=0; i<platforms.size(); ++i) {
|
||||
LwjglPlatform platform = platforms.get(i);
|
||||
platformInfos.append("\n * Platform ").append(i+1);
|
||||
platformInfos.append("\n * Name: ").append(platform.getName());
|
||||
platformInfos.append("\n * Vendor: ").append(platform.getVendor());
|
||||
platformInfos.append("\n * Version: ").append(platform.getVersion());
|
||||
platformInfos.append("\n * Profile: ").append(platform.getProfile());
|
||||
platformInfos.append("\n * Supports interop: ").append(platform.hasOpenGLInterop());
|
||||
List<LwjglDevice> devices = platform.getDevices();
|
||||
platformInfos.append("\n * Available devices:");
|
||||
for (int j=0; j<devices.size(); ++j) {
|
||||
LwjglDevice device = devices.get(j);
|
||||
platformInfos.append("\n * * Device ").append(j+1);
|
||||
platformInfos.append("\n * * Name: ").append(device.getName());
|
||||
platformInfos.append("\n * * Vendor: ").append(device.getVendor());
|
||||
platformInfos.append("\n * * Version: ").append(device.getVersion());
|
||||
platformInfos.append("\n * * Profile: ").append(device.getProfile());
|
||||
platformInfos.append("\n * * Compiler version: ").append(device.getCompilerVersion());
|
||||
platformInfos.append("\n * * Device type: ").append(device.getDeviceType());
|
||||
platformInfos.append("\n * * Compute units: ").append(device.getComputeUnits());
|
||||
platformInfos.append("\n * * Work group size: ").append(device.getMaxiumWorkItemsPerGroup());
|
||||
platformInfos.append("\n * * Global memory: ").append(device.getGlobalMemorySize()).append("B");
|
||||
platformInfos.append("\n * * Local memory: ").append(device.getLocalMemorySize()).append("B");
|
||||
platformInfos.append("\n * * Constant memory: ").append(device.getMaximumConstantBufferSize()).append("B");
|
||||
platformInfos.append("\n * * Supports double: ").append(device.hasDouble());
|
||||
platformInfos.append("\n * * Supports half floats: ").append(device.hasHalfFloat());
|
||||
platformInfos.append("\n * * Supports writable 3d images: ").append(device.hasWritableImage3D());
|
||||
platformInfos.append("\n * * Supports interop: ").append(device.hasOpenGLInterop());
|
||||
}
|
||||
}
|
||||
logger.info(platformInfos.toString());
|
||||
|
||||
//choose devices
|
||||
PlatformChooser chooser = null;
|
||||
if (settings.getOpenCLPlatformChooser() != null) {
|
||||
try {
|
||||
chooser = (PlatformChooser) Class.forName(settings.getOpenCLPlatformChooser()).newInstance();
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.WARNING, "unable to instantiate custom PlatformChooser", ex);
|
||||
}
|
||||
}
|
||||
if (chooser == null) {
|
||||
chooser = new DefaultPlatformChooser();
|
||||
}
|
||||
List<? extends Device> choosenDevices = chooser.chooseDevices(platforms);
|
||||
List<CLDevice> devices = new ArrayList<>(choosenDevices.size());
|
||||
LwjglPlatform platform = null;
|
||||
for (Device d : choosenDevices) {
|
||||
if (!(d instanceof LwjglDevice)) {
|
||||
logger.log(Level.SEVERE, "attempt to return a custom Device implementation from PlatformChooser: {0}", d);
|
||||
return;
|
||||
}
|
||||
LwjglDevice ld = (LwjglDevice) d;
|
||||
if (platform == null) {
|
||||
platform = ld.getPlatform();
|
||||
} else if (platform != ld.getPlatform()) {
|
||||
logger.severe("attempt to use devices from different platforms");
|
||||
return;
|
||||
}
|
||||
devices.add(ld.getDevice());
|
||||
}
|
||||
if (devices.isEmpty()) {
|
||||
logger.warning("no devices specified, no OpenCL context created");
|
||||
return;
|
||||
}
|
||||
clPlatform = platform;
|
||||
logger.log(Level.INFO, "chosen platform: {0}", platform.getName());
|
||||
logger.log(Level.INFO, "chosen devices: {0}", choosenDevices);
|
||||
|
||||
//create context
|
||||
try {
|
||||
CLContext c = CLContext.create(platform.getPlatform(), devices, null, Display.getDrawable(), null);
|
||||
clContext = new com.jme3.opencl.lwjgl.LwjglContext(c, (List<LwjglDevice>) choosenDevices);
|
||||
} catch (LWJGLException ex) {
|
||||
logger.log(Level.SEVERE, "Unable to create OpenCL context", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("OpenCL context created");
|
||||
}
|
||||
|
||||
public void internalDestroy() {
|
||||
renderer = null;
|
||||
timer = null;
|
||||
@ -311,4 +422,8 @@ public abstract class LwjglContext implements JmeContext {
|
||||
return timer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.jme3.opencl.Context getOpenCLContext() {
|
||||
return clContext;
|
||||
}
|
||||
}
|
||||
|
@ -149,6 +149,10 @@ public class LwjglDisplay extends LwjglAbstractDisplay {
|
||||
GL11.glEnable(ARBMultisample.GL_MULTISAMPLE_ARB);
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.isOpenCLSupport()) {
|
||||
initOpenCL();
|
||||
}
|
||||
}
|
||||
|
||||
protected void destroyContext(){
|
||||
|
238
jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java
Normal file
238
jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
303
jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java
Normal file
303
jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
579
jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java
Normal file
579
jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
233
jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java
Normal file
233
jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
163
jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/Utils.java
Normal file
163
jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/Utils.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -35,6 +35,13 @@ package com.jme3.system.lwjgl;
|
||||
import com.jme3.input.lwjgl.GlfwJoystickInput;
|
||||
import com.jme3.input.lwjgl.GlfwKeyInput;
|
||||
import com.jme3.input.lwjgl.GlfwMouseInput;
|
||||
import com.jme3.opencl.Context;
|
||||
import com.jme3.opencl.DefaultPlatformChooser;
|
||||
import com.jme3.opencl.Device;
|
||||
import com.jme3.opencl.PlatformChooser;
|
||||
import com.jme3.opencl.lwjgl.LwjglDevice;
|
||||
import com.jme3.opencl.lwjgl.LwjglPlatform;
|
||||
import com.jme3.opencl.lwjgl.Utils;
|
||||
import com.jme3.renderer.Renderer;
|
||||
import com.jme3.renderer.RendererException;
|
||||
import com.jme3.renderer.lwjgl.LwjglGL;
|
||||
@ -43,17 +50,21 @@ import com.jme3.renderer.lwjgl.LwjglGLFboEXT;
|
||||
import com.jme3.renderer.lwjgl.LwjglGLFboGL3;
|
||||
import com.jme3.renderer.opengl.*;
|
||||
import com.jme3.system.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.lwjgl.PointerBuffer;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.opencl.*;
|
||||
import org.lwjgl.opengl.ARBDebugOutput;
|
||||
import org.lwjgl.opengl.ARBFramebufferObject;
|
||||
import org.lwjgl.opengl.EXTFramebufferMultisample;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_TRUE;
|
||||
import org.lwjgl.opengl.ARBDebugOutput;
|
||||
|
||||
import static org.lwjgl.opencl.CL10.CL_CONTEXT_PLATFORM;
|
||||
import static org.lwjgl.opengl.GL.createCapabilities;
|
||||
import static org.lwjgl.opengl.GL11.glGetInteger;
|
||||
|
||||
@ -64,6 +75,8 @@ public abstract class LwjglContext implements JmeContext {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LwjglContext.class.getName());
|
||||
|
||||
public static final boolean CL_GL_SHARING_POSSIBLE = true;
|
||||
|
||||
protected static final String THREAD_NAME = "jME3 Main";
|
||||
|
||||
protected AtomicBoolean created = new AtomicBoolean(false);
|
||||
@ -77,6 +90,8 @@ public abstract class LwjglContext implements JmeContext {
|
||||
protected GlfwJoystickInput joyInput;
|
||||
protected Timer timer;
|
||||
protected SystemListener listener;
|
||||
|
||||
protected com.jme3.opencl.lwjgl.LwjglContext clContext;
|
||||
|
||||
public void setSystemListener(SystemListener listener) {
|
||||
this.listener = listener;
|
||||
@ -180,6 +195,149 @@ public abstract class LwjglContext implements JmeContext {
|
||||
joyInput.initialize();
|
||||
}
|
||||
renderable.set(true);
|
||||
|
||||
}
|
||||
|
||||
protected void initOpenCL(long window) {
|
||||
logger.info("Initialize OpenCL with LWJGL3");
|
||||
|
||||
// try {
|
||||
// CL.create();
|
||||
// } catch (Exception ex) {
|
||||
// logger.log(Level.SEVERE, "Unable to initialize OpenCL", ex);
|
||||
// return;
|
||||
// }
|
||||
|
||||
//load platforms and devices
|
||||
StringBuilder platformInfos = new StringBuilder();
|
||||
ArrayList<LwjglPlatform> platforms = new ArrayList<>();
|
||||
for (CLPlatform p : CLPlatform.getPlatforms()) {
|
||||
platforms.add(new LwjglPlatform(p));
|
||||
}
|
||||
platformInfos.append("Available OpenCL platforms:");
|
||||
for (int i=0; i<platforms.size(); ++i) {
|
||||
LwjglPlatform platform = platforms.get(i);
|
||||
platformInfos.append("\n * Platform ").append(i+1);
|
||||
platformInfos.append("\n * Name: ").append(platform.getName());
|
||||
platformInfos.append("\n * Vendor: ").append(platform.getVendor());
|
||||
platformInfos.append("\n * Version: ").append(platform.getVersion());
|
||||
platformInfos.append("\n * Profile: ").append(platform.getProfile());
|
||||
platformInfos.append("\n * Supports interop: ").append(platform.hasOpenGLInterop());
|
||||
List<LwjglDevice> devices = platform.getDevices();
|
||||
platformInfos.append("\n * Available devices:");
|
||||
for (int j=0; j<devices.size(); ++j) {
|
||||
LwjglDevice device = devices.get(j);
|
||||
platformInfos.append("\n * * Device ").append(j+1);
|
||||
platformInfos.append("\n * * Name: ").append(device.getName());
|
||||
platformInfos.append("\n * * Vendor: ").append(device.getVendor());
|
||||
platformInfos.append("\n * * Version: ").append(device.getVersion());
|
||||
platformInfos.append("\n * * Profile: ").append(device.getProfile());
|
||||
platformInfos.append("\n * * Compiler version: ").append(device.getCompilerVersion());
|
||||
platformInfos.append("\n * * Device type: ").append(device.getDeviceType());
|
||||
platformInfos.append("\n * * Compute units: ").append(device.getComputeUnits());
|
||||
platformInfos.append("\n * * Work group size: ").append(device.getMaxiumWorkItemsPerGroup());
|
||||
platformInfos.append("\n * * Global memory: ").append(device.getGlobalMemorySize()).append("B");
|
||||
platformInfos.append("\n * * Local memory: ").append(device.getLocalMemorySize()).append("B");
|
||||
platformInfos.append("\n * * Constant memory: ").append(device.getMaximumConstantBufferSize()).append("B");
|
||||
platformInfos.append("\n * * Supports double: ").append(device.hasDouble());
|
||||
platformInfos.append("\n * * Supports half floats: ").append(device.hasHalfFloat());
|
||||
platformInfos.append("\n * * Supports writable 3d images: ").append(device.hasWritableImage3D());
|
||||
platformInfos.append("\n * * Supports interop: ").append(device.hasOpenGLInterop());
|
||||
}
|
||||
}
|
||||
logger.info(platformInfos.toString());
|
||||
|
||||
//choose devices
|
||||
PlatformChooser chooser = null;
|
||||
if (settings.getOpenCLPlatformChooser() != null) {
|
||||
try {
|
||||
chooser = (PlatformChooser) Class.forName(settings.getOpenCLPlatformChooser()).newInstance();
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.WARNING, "unable to instantiate custom PlatformChooser", ex);
|
||||
}
|
||||
}
|
||||
if (chooser == null) {
|
||||
chooser = new DefaultPlatformChooser();
|
||||
}
|
||||
List<? extends Device> choosenDevices = chooser.chooseDevices(platforms);
|
||||
List<CLDevice> devices = new ArrayList<>(choosenDevices.size());
|
||||
LwjglPlatform platform = null;
|
||||
for (Device d : choosenDevices) {
|
||||
if (!(d instanceof LwjglDevice)) {
|
||||
logger.log(Level.SEVERE, "attempt to return a custom Device implementation from PlatformChooser: {0}", d);
|
||||
return;
|
||||
}
|
||||
LwjglDevice ld = (LwjglDevice) d;
|
||||
if (platform == null) {
|
||||
platform = ld.getPlatform();
|
||||
} else if (platform != ld.getPlatform()) {
|
||||
logger.severe("attempt to use devices from different platforms");
|
||||
return;
|
||||
}
|
||||
devices.add(ld.getCLDevice());
|
||||
}
|
||||
if (devices.isEmpty()) {
|
||||
logger.warning("no devices specified, no OpenCL context created");
|
||||
return;
|
||||
}
|
||||
logger.log(Level.INFO, "chosen platform: {0}", platform.getName());
|
||||
logger.log(Level.INFO, "chosen devices: {0}", choosenDevices);
|
||||
|
||||
//create context
|
||||
try {
|
||||
long c = createContext(platform.getPlatform(), devices, window);
|
||||
clContext = new com.jme3.opencl.lwjgl.LwjglContext(c, (List<LwjglDevice>) choosenDevices);
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "Unable to create OpenCL context", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("OpenCL context created");
|
||||
}
|
||||
private long createContext(final CLPlatform platform, final List<CLDevice> devices, long window) throws Exception {
|
||||
|
||||
final int propertyCount = 2 + 4 + 1;
|
||||
|
||||
final PointerBuffer properties = PointerBuffer.allocateDirect(propertyCount + devices.size());
|
||||
|
||||
//set sharing properties
|
||||
//https://github.com/glfw/glfw/issues/104
|
||||
//https://github.com/LWJGL/lwjgl3/blob/master/modules/core/src/test/java/org/lwjgl/demo/opencl/Mandelbrot.java
|
||||
//TODO: test on Linus and MacOSX
|
||||
switch (org.lwjgl.system.Platform.get()) {
|
||||
case WINDOWS:
|
||||
properties
|
||||
.put(KHRGLSharing.CL_GL_CONTEXT_KHR)
|
||||
.put(org.lwjgl.glfw.GLFWNativeWGL.glfwGetWGLContext(window))
|
||||
.put(KHRGLSharing.CL_WGL_HDC_KHR)
|
||||
.put(org.lwjgl.opengl.WGL.wglGetCurrentDC());
|
||||
break;
|
||||
case LINUX:
|
||||
properties
|
||||
.put(KHRGLSharing.CL_GL_CONTEXT_KHR)
|
||||
.put(org.lwjgl.glfw.GLFWNativeGLX.glfwGetGLXContext(window))
|
||||
.put(KHRGLSharing.CL_GLX_DISPLAY_KHR)
|
||||
.put(org.lwjgl.glfw.GLFWNativeX11.glfwGetX11Display());
|
||||
break;
|
||||
case MACOSX:
|
||||
properties
|
||||
.put(APPLEGLSharing.CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE)
|
||||
.put(org.lwjgl.opengl.CGL.CGLGetShareGroup(org.lwjgl.opengl.CGL.CGLGetCurrentContext()));
|
||||
}
|
||||
properties.put(CL_CONTEXT_PLATFORM).put(platform);
|
||||
properties.put(0);
|
||||
properties.flip();
|
||||
|
||||
Utils.errorBuffer.rewind();
|
||||
PointerBuffer deviceBuffer = PointerBuffer.allocateDirect(devices.size());
|
||||
for (CLDevice d : devices) {
|
||||
deviceBuffer.put(d);
|
||||
}
|
||||
deviceBuffer.flip();
|
||||
long context = CL10.clCreateContext(properties, deviceBuffer, null, 0, Utils.errorBuffer);
|
||||
Utils.checkError(Utils.errorBuffer, "clCreateContext");
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
public void internalDestroy() {
|
||||
@ -250,4 +408,9 @@ public abstract class LwjglContext implements JmeContext {
|
||||
return timer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getOpenCLContext() {
|
||||
return clContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -326,6 +326,13 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
|
||||
|
||||
created.set(true);
|
||||
super.internalCreate();
|
||||
|
||||
//create OpenCL
|
||||
//Must be done here because the window handle is needed
|
||||
if (settings.isOpenCLSupport()) {
|
||||
initOpenCL(window);
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
try {
|
||||
if (window != NULL) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user