From ab15f5c57c20caaeb3b8cdae2367604b660a7f94 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Sun, 17 Apr 2016 21:14:57 +0200 Subject: [PATCH 01/40] started with the OpenCL api for jme3 --- .../src/main/java/com/jme3/opencl/Buffer.java | 130 +++++++++++++ .../java/com/jme3/opencl/CommandQueue.java | 129 ++++++++++++ .../main/java/com/jme3/opencl/Context.java | 164 ++++++++++++++++ .../src/main/java/com/jme3/opencl/Event.java | 52 +++++ .../src/main/java/com/jme3/opencl/Kernel.java | 183 ++++++++++++++++++ .../main/java/com/jme3/opencl/LocalMem.java | 71 +++++++ .../com/jme3/opencl/LocalMemPerElement.java | 71 +++++++ .../java/com/jme3/opencl/MappingAccess.java | 43 ++++ .../java/com/jme3/opencl/MemoryAccess.java | 43 ++++ .../main/java/com/jme3/opencl/Program.java | 56 ++++++ .../main/java/com/jme3/opencl/WorkSize.java | 111 +++++++++++ .../java/com/jme3/opencl/package-info.java | 38 ++++ 12 files changed, 1091 insertions(+) create mode 100644 jme3-core/src/main/java/com/jme3/opencl/Buffer.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/Context.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/Event.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/Kernel.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/LocalMem.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/LocalMemPerElement.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/MappingAccess.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/MemoryAccess.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/Program.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/WorkSize.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/package-info.java diff --git a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java new file mode 100644 index 000000000..71d80f843 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java @@ -0,0 +1,130 @@ +/* + * 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; + +/** + * + * @author Sebastian Weiss + */ +public class Buffer { + + private final long buffer; + + public Buffer(long buffer) { + this.buffer = buffer; + } + + public int getSize() { + throw new UnsupportedOperationException("not supported yet"); + } + + public MemoryAccess getMemoryAccessFlags() { + throw new UnsupportedOperationException("not supported yet"); + } + + public void read(CommandQueue queue, Buffer src, ByteBuffer dest, int size, int offset) { + queue.read(src, dest, size, offset); + } + public void read(CommandQueue queue, Buffer src, ByteBuffer dest, int size) { + queue.read(src, dest, size); + } + public void read(CommandQueue queue, Buffer src, ByteBuffer dest) { + queue.read(src, dest); + } + + public Event readAsync(CommandQueue queue, Buffer src, ByteBuffer dest, int size, int offset) { + return queue.readAsync(src, dest, size, offset); + } + public Event readAsync(CommandQueue queue, Buffer src, ByteBuffer dest, int size) { + return queue.readAsync(src, dest, size); + } + public Event readAsync(CommandQueue queue, Buffer src, ByteBuffer dest) { + return queue.readAsync(src, dest); + } + + public void write(CommandQueue queue, ByteBuffer src, Buffer dest, int size, int offset) { + queue.write(src, dest, size, offset); + } + public void write(CommandQueue queue, ByteBuffer src, Buffer dest, int size) { + queue.write(src, dest, size); + } + public void write(CommandQueue queue, ByteBuffer src, Buffer dest) { + queue.write(src, dest); + } + + public Event writeAsync(CommandQueue queue, ByteBuffer src, Buffer dest, int size, int offset) { + return queue.writeAsync(src, dest, size, offset); + } + public Event writeAsync(CommandQueue queue, ByteBuffer src, Buffer dest, int size) { + return queue.writeAsync(src, dest, size); + } + public Event writeAsync(CommandQueue queue, ByteBuffer src, Buffer dest) { + return queue.writeAsync(src, dest); + } + + public void copyTo(CommandQueue queue, Buffer src, Buffer dest, int size, int srcOffset, int destOffset) { + queue.copyTo(src, dest, size, srcOffset, destOffset); + } + public void copyTo(CommandQueue queue, Buffer src, Buffer dest, int size) { + queue.copyTo(src, dest, size); + } + public void copyTo(CommandQueue queue, Buffer src, Buffer dest) { + queue.copyTo(src, dest); + } + + public Event copyToAsync(CommandQueue queue, Buffer src, Buffer dest, int size, int srcOffset, int destOffset) { + return queue.copyToAsync(src, dest, size, srcOffset, destOffset); + } + public Event copyToAsync(CommandQueue queue, Buffer src, Buffer dest, int size) { + return queue.copyToAsync(src, dest, size); + } + public Event copyToAsync(CommandQueue queue, Buffer src, Buffer dest) { + return queue.copyToAsync(src, dest); + } + + public ByteBuffer map(CommandQueue queue, Buffer src, int size, int offset, MappingAccess access) { + return queue.map(src, size, offset, access); + } + public ByteBuffer map(CommandQueue queue, Buffer src, int size, MappingAccess access) { + return queue.map(src, size, access); + } + public ByteBuffer map(CommandQueue queue, Buffer src, MappingAccess access) { + return queue.map(src, access); + } + public void unmap(CommandQueue queue, Buffer src, ByteBuffer ptr) { + queue.unmap(src, ptr); + } + + //TODO: async mapping +} diff --git a/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java new file mode 100644 index 000000000..a25675e7a --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java @@ -0,0 +1,129 @@ +/* + * 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; + +/** + * + * @author Sebastian Weiss + */ +public final class CommandQueue { + private final long queue; + + public CommandQueue(long queue) { + this.queue = queue; + } + + public void read(Buffer src, ByteBuffer dest, int size, int offset) { + throw new UnsupportedOperationException("not supported yet"); + } + public void read(Buffer src, ByteBuffer dest, int size) { + read(src, dest, size, 0); + } + public void read(Buffer src, ByteBuffer dest) { + read(src, dest, src.getSize(), 0); + } + + public Event readAsync(Buffer src, ByteBuffer dest, int size, int offset) { + throw new UnsupportedOperationException("not supported yet"); + } + public Event readAsync(Buffer src, ByteBuffer dest, int size) { + return readAsync(src, dest, size, 0); + } + public Event readAsync(Buffer src, ByteBuffer dest) { + return readAsync(src, dest, src.getSize()); + } + + public void write(ByteBuffer src, Buffer dest, int size, int offset) { + throw new UnsupportedOperationException("not supported yet"); + } + public void write(ByteBuffer src, Buffer dest, int size) { + write(src, dest, size, 0); + } + public void write(ByteBuffer src, Buffer dest) { + write(src, dest, dest.getSize()); + } + + public Event writeAsync(ByteBuffer src, Buffer dest, int size, int offset) { + throw new UnsupportedOperationException("not supported yet"); + } + public Event writeAsync(ByteBuffer src, Buffer dest, int size) { + return writeAsync(src, dest, size, 0); + } + public Event writeAsync(ByteBuffer src, Buffer dest) { + return writeAsync(src, dest, dest.getSize()); + } + + public void copyTo(Buffer src, Buffer dest, int size, int srcOffset, int destOffset) { + throw new UnsupportedOperationException("not supported yet"); + } + public void copyTo(Buffer src, Buffer dest, int size) { + copyTo(src, dest, size, 0, 0); + } + public void copyTo(Buffer src, Buffer dest) { + copyTo(src, dest, src.getSize()); + } + + public Event copyToAsync(Buffer src, Buffer dest, int size, int srcOffset, int destOffset) { + throw new UnsupportedOperationException("not supported yet"); + } + public Event copyToAsync(Buffer src, Buffer dest, int size) { + return copyToAsync(src, dest, size, 0, 0); + } + public Event copyToAsync(Buffer src, Buffer dest) { + return copyToAsync(src, dest, src.getSize()); + } + + public ByteBuffer map(Buffer src, int size, int offset, MappingAccess access) { + throw new UnsupportedOperationException("not supported yet"); + } + public ByteBuffer map(Buffer src, int size, MappingAccess access) { + return map(src, size, 0, access); + } + public ByteBuffer map(Buffer src, MappingAccess access) { + return map(src, src.getSize(), access); + } + public void unmap(Buffer src, ByteBuffer ptr) { + throw new UnsupportedOperationException("not supported yet"); + } + + //TODO: async mapping + + public void flush() { + throw new UnsupportedOperationException("not supported yet"); + } + public void finish() { + throw new UnsupportedOperationException("not supported yet"); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java new file mode 100644 index 000000000..e8d1c3c2c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -0,0 +1,164 @@ +/* + * 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.scene.VertexBuffer; +import com.jme3.scene.mesh.IndexBuffer; +import com.jme3.scene.mesh.IndexByteBuffer; +import com.jme3.scene.mesh.IndexIntBuffer; +import com.jme3.scene.mesh.IndexShortBuffer; +import com.jme3.texture.Image; +import java.nio.ByteBuffer; +import java.util.List; + +/** + * The central OpenCL context. Every actions start from here. + * @author Sebastian Weiss + */ +public final class Context { + + private final long context; + + public Context(long context) { + this.context = context; + } + + public CommandQueue createQueue() { + throw new UnsupportedOperationException("not supported yet"); + } + //TODO: constructor with specific device and properties + + public Buffer createBuffer(int size, MemoryAccess access) { + throw new UnsupportedOperationException("not supported yet"); + } + public Buffer createBuffer(int size) { + return createBuffer(size, MemoryAccess.READ_WRITE); + } + + public Buffer useHostBuffer(ByteBuffer data, int size, MemoryAccess access) { + throw new UnsupportedOperationException("not supported yet"); + } + public Buffer useHostBuffer(ByteBuffer data, int size) { + return useHostBuffer(data, size, MemoryAccess.READ_WRITE); + } + + public static enum ImageChannelOrder { + R, Rx, A, + INTENSITY, + LUMINANCE, + RG, RGx, RA, + RGB, RGBx, + RGBA, + ARGB, BGRA + } + public static enum ImageChannelType { + SNORM_INT8, + SNORM_INT16, + UNORM_INT8, + UNROM_INT16, + UNORM_SHORT_565, + UNROM_SHORT_555, + UNORM_INT_101010, + SIGNED_INT8, + SIGNED_INT16, + SIGNED_INT32, + UNSIGNED_INT8, + UNSIGNED_INT16, + UNSIGNED_INT32, + HALF_FLOAT, + FLOAT + } + public static class ImageFormat { //Struct + public ImageChannelOrder channelOrder; + public ImageChannelType channelType; + } + public static enum ImageType { + IMAGE_1D, + IMAGE_1D_BUFFER, + IMAGE_2D, + IMAGE_3D, + IMAGE_1D_ARRAY, + IMAGE_2D_ARRAY + } + public static class ImageDescriptor { //Struct + public ImageType type; + public int width; + public int height; + public int depth; + public int arraySize; + public int rowPitch; + public int slicePitch; + public int numMipLevels; + public int numSamples; + public Buffer buffer; + } + public Buffer createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr, ByteBuffer hostPtr) { + throw new UnsupportedOperationException("not supported yet"); + } + //TODO: add simplified methods for 1D, 2D, 3D textures + + //Interop + + public Buffer bindVertexBuffer(VertexBuffer vb) { + throw new UnsupportedOperationException("not supported yet"); + } + public Buffer bindIndexBuffer(IndexBuffer ib) { + if (!(ib instanceof IndexByteBuffer) + && !(ib instanceof IndexShortBuffer) + && !(ib instanceof IndexIntBuffer)) { + throw new IllegalArgumentException("Index buffer must be an IndexByteBuffer, IndexShortBuffer or IndexIntBuffer"); + } + throw new UnsupportedOperationException("not supported yet"); + } + public Buffer bindImage(Image image) { + throw new UnsupportedOperationException("not supported yet"); + } + + public Program createProgramFromSourceCode(String sourceCode) { + throw new UnsupportedOperationException("not supported yet"); + } + public Program createProgramFromSourceFilesWithInclude( + String include, String... resources) { + //TODO: load resources + throw new UnsupportedOperationException("not implemented yet"); + } + public Program createProgramFormSourcesWithInclude(String include, List resources) { + return createProgramFromSourceFilesWithInclude(include, resources.toArray(new String[resources.size()])); + } + public Program createProgramFromSources(String... resources) { + return createProgramFromSourceFilesWithInclude(null, resources); + } + public Program createProgramFromSources(List resources) { + return createProgramFormSourcesWithInclude(null, resources); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/opencl/Event.java b/jme3-core/src/main/java/com/jme3/opencl/Event.java new file mode 100644 index 000000000..ec08d764b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/Event.java @@ -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; + +/** + * + * @author Sebastian Weiss + */ +public final class Event { + private final long event; + + public Event(long event) { + this.event = event; + } + + public void waitForFinished() { + throw new UnsupportedOperationException("not supported yet"); + } + + public boolean isCompleted() { + throw new UnsupportedOperationException("not supported yet"); + } +} diff --git a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java new file mode 100644 index 000000000..4da0668f8 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java @@ -0,0 +1,183 @@ +/* + * 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.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector4f; + +/** + * + * @author Sebastian Weiss + */ +public final class Kernel { + private final WorkSize globalWorkSize; + private final WorkSize workGroupSize; + private final long kernel; + + public Kernel(long kernel) { + this.kernel = kernel; + this.globalWorkSize = new WorkSize(0); + this.workGroupSize = new WorkSize(0); + } + + public String getName() { + throw new UnsupportedOperationException("not supported yet"); + } + public int getArgCount() { + throw new UnsupportedOperationException("not supported yet"); + } + + public WorkSize getGlobalWorkSize() { + return globalWorkSize; + } + public void setGlobalWorkSize(WorkSize ws) { + globalWorkSize.set(ws); + } + public void setGlobalWorkSize(int size) { + globalWorkSize.set(1, size); + } + public void setGlobalWorkSize(int width, int height) { + globalWorkSize.set(2, width, height); + } + public void setGlobalWorkSize(int width, int height, int depth) { + globalWorkSize.set(3, width, height, depth); + } + + public WorkSize getWorkGroupSize() { + return workGroupSize; + } + public void setWorkGroupSize(WorkSize ws) { + workGroupSize.set(ws); + } + public void setWorkGroupSize(int size) { + workGroupSize.set(1, size); + } + public void setWorkGroupSize(int width, int height) { + workGroupSize.set(2, width, height); + } + public void setWorkGroupSize(int width, int height, int depth) { + workGroupSize.set(3, width, height, depth); + } + public void setWorkGroupSizeToNull() { + workGroupSize.set(1, 0); + } + + public void setArg(int index, LocalMemPerElement t) { + throw new UnsupportedOperationException("not supported yet"); + } + public void setArg(int index, LocalMem t) { + throw new UnsupportedOperationException("not supported yet"); + } + public void setArg(int index, Buffer t) { + throw new UnsupportedOperationException("not supported yet"); + } + public void setArg(int index, byte b) { + throw new UnsupportedOperationException("not supported yet"); + } + public void setArg(int index, short s) { + throw new UnsupportedOperationException("not supported yet"); + } + public void setArg(int index, int i) { + throw new UnsupportedOperationException("not supported yet"); + } + public void setArg(int index, long l) { + throw new UnsupportedOperationException("not supported yet"); + } + public void setArg(int index, float f) { + throw new UnsupportedOperationException("not supported yet"); + } + public void setArg(int index, double d) { + throw new UnsupportedOperationException("not supported yet"); + } + public void setArg(int index, Vector2f v) { + throw new UnsupportedOperationException("not supported yet"); + } + //Vector3f not supported because cl_float3 is the same as a float4 + public void setArg(int index, Vector4f v) { + throw new UnsupportedOperationException("not supported yet"); + } + public void setArg(int index, Quaternion q) { + throw new UnsupportedOperationException("not supported yet"); + } + 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 LocalMemPerElement) { + setArg(index, (LocalMemPerElement) arg); + } else if (arg instanceof LocalMem) { + setArg(index, (LocalMem) arg); + } else if (arg instanceof Buffer) { + setArg(index, (Buffer) arg); + } else { + throw new IllegalArgumentException("unknown kernel argument type: "+arg); + } + } + private void setArgs(Object... args) { + for (int i=0; i3) { + 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; + } + + +} diff --git a/jme3-core/src/main/java/com/jme3/opencl/package-info.java b/jme3-core/src/main/java/com/jme3/opencl/package-info.java new file mode 100644 index 000000000..66aa0db47 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/package-info.java @@ -0,0 +1,38 @@ +/* + * 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. + */ +package com.jme3.opencl; + +//TODO: add profiling to Kernel, CommandQueue From 195a5a69be1d2662c94291c19867c517d5b75591 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Mon, 18 Apr 2016 17:38:38 +0200 Subject: [PATCH 02/40] added first version of the cl wrapper in CL.java, contains a subset of the OpenCL specification --- .../src/main/java/com/jme3/opencl/Buffer.java | 4 + .../src/main/java/com/jme3/opencl/CL.java | 143 ++++++++++++++ .../java/com/jme3/opencl/CommandQueue.java | 4 + .../main/java/com/jme3/opencl/Context.java | 4 + .../src/main/java/com/jme3/opencl/Device.java | 174 ++++++++++++++++++ .../opencl/KernelCompilationException.java | 48 +++++ .../java/com/jme3/opencl/OpenCLException.java | 71 +++++++ 7 files changed, 448 insertions(+) create mode 100644 jme3-core/src/main/java/com/jme3/opencl/CL.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/Device.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/KernelCompilationException.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java diff --git a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java index 71d80f843..ca1f86409 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java @@ -127,4 +127,8 @@ public class Buffer { } //TODO: async mapping + + //TODO: clEnqueueFillBuffer + + //TODO: image read/write } diff --git a/jme3-core/src/main/java/com/jme3/opencl/CL.java b/jme3-core/src/main/java/com/jme3/opencl/CL.java new file mode 100644 index 000000000..71ae9d5b5 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/CL.java @@ -0,0 +1,143 @@ +/* + * 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.*; + +/** + * Interface for OpenCL implementations + * @author Sebastian Weiss + */ +public interface CL { + + //temp buffers for argument passing + public static class TempBuffer { + /** + * 16-Bytes (4 floats) of a byte buffer + */ + public final ByteBuffer b16; + /** + * Short-buffer view on b16 + */ + public final ShortBuffer b16s; + /** + * int buffer view on b16 + */ + public final IntBuffer b16i; + /** + * long buffer view on b16 + */ + public final LongBuffer b16l; + /** + * float buffer view on b16 + */ + public final FloatBuffer b16f; + /** + * double buffer view on b16 + */ + public final DoubleBuffer b16d; + + public TempBuffer(ByteBuffer b16) { + this.b16 = b16; + b16.rewind(); + this.b16s = b16.asShortBuffer(); + this.b16i = b16.asIntBuffer(); + this.b16l = b16.asLongBuffer(); + this.b16f = b16.asFloatBuffer(); + this.b16d = b16.asDoubleBuffer(); + } + } + /** + * Returns up to 4 temp buffer instances + * @return + */ + TempBuffer[] getTempBuffers(); + + //entry point + long getContext(); + + //OpenCL functions + long clCreateCommandQueue(long context, long device, boolean profiling); + void clReleaseCommandQueue(long queue); + + long clCreateBuffer(long context, MemoryAccess access, int size, ByteBuffer hostPtr); + long clEnqueueReadBuffer(long queue, long buffer, boolean blocking, int offset, int size, ByteBuffer ptr); + long clEnqueueWriteBuffer(long queue, long buffer, boolean blocking, int offset, int size, ByteBuffer ptr); + long clEnqueueCopyBuffer(long queue, long srcBuffer, long dstBuffer, int srcOffset, int dstOffset, int size); + long clEnqueueFillBuffer(long queue, long buffer, ByteBuffer pattern, int patternSize, int offset, int size); + long clEnqueueMapBuffer(long queue, long buffer, boolean blocking, MappingAccess flags, int offset, int size); + + long clCreateImage(long context, MemoryAccess access, Context.ImageFormat format, Context.ImageDescriptor desc, ByteBuffer ptr); + Context.ImageFormat[] clGetSupportedImageFormats(long context, MemoryAccess ma, Context.ImageType type); + + long clEnqueueReadImage(long queue, long image, boolean blocking, ByteBuffer origin, ByteBuffer region, int rowPitch, int slicePitch, ByteBuffer ptr); + long clEnqueueWriteImage(long queue, long image, boolean blocking, ByteBuffer origin, ByteBuffer region, int inputRowPitch, int intputSlicePitch, ByteBuffer ptr); + long clEnqueueCopyImage(long queue, long srcImage, long dstImage, ByteBuffer srcOrigin, ByteBuffer dstOrigin, ByteBuffer region); + long clEnqueueFillImage(long queue, long image, ByteBuffer fillColor, ByteBuffer origin, ByteBuffer region); + + long clEnqueueCopyImageToBuffer(long queue, long srcImage, long dstBuffer, ByteBuffer srcOrigin, ByteBuffer region, int dstOffset); + long clEnqueueCopyBufferToImage(long queue, long srcBuffer, long dstImage, int srcOffset, ByteBuffer dstOrigin, ByteBuffer region); + + long clEnqueueMapImage(long queue, long image, boolean blocking, MappingAccess ma, ByteBuffer origin, ByteBuffer region, int rowPitch, int slicePitch); + //TODO: clGetImageInfo + + void clReleaseMemObject(long mem); + long clEnqueueUnmapMemObject(long queue, long mem, ByteBuffer ptr); + int getMemSize(long mem); //uses clGetMemObjectInfo + + long clCreateProgramWithSource(long context, CharSequence[] sources); + //TODO: create from binary + long clReleaseProgram(long program); + + void clBuildProgram(long program, long[] devices, CharSequence optpions) throws KernelCompilationException; + String getKernelNames(long program); //uses clGetProgramInfo + + long clCreateKernel(long program, String kernelName); + void clReleaseKernel(long kernel); + void clSetKernelArg(long kernel, int argIndex, int argSize, ByteBuffer argValue); + String getKernelName(long kernel); //uses clGetKernelInfo + int getKernelNumArgs(long kernel); //uses clGetKernelInfo + //TODO: clGetKernelWorkGroupInfo + + long clEnqueueNDRangeKernel(long queue, long kernel, int workDim, + ByteBuffer globalWorkOffset, ByteBuffer globalWorkSize, ByteBuffer localWorkSize); + + void clWaitForEvents(long[] events); + void clWaitForEvent(long event); + boolean isEventCompleted(long event); //uses clGetEventInfo + void clReleaseEvent(long event); + + void clFlush(long queue); + void clFinish(long queue); + + +} diff --git a/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java index a25675e7a..6354677fa 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java +++ b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java @@ -119,6 +119,10 @@ public final class CommandQueue { //TODO: async mapping + //TODO: clEnqueueFillBuffer + + //TODO: image read/write + public void flush() { throw new UnsupportedOperationException("not supported yet"); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index e8d1c3c2c..4e3063fc9 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -52,6 +52,10 @@ public final class Context { this.context = context; } + public List getDevices() { + throw new UnsupportedOperationException("not supported yet"); + } + public CommandQueue createQueue() { throw new UnsupportedOperationException("not supported yet"); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Device.java b/jme3-core/src/main/java/com/jme3/opencl/Device.java new file mode 100644 index 000000000..045b44ecb --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/Device.java @@ -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 com.jme3.opencl; + +import java.util.Collection; + +/** + * + * @author Sebastian Weiss + */ +public final class Device { + private final long device; + + public Device(long device) { + this.device = device; + } + + public static enum DeviceType { + DEFAULT, + CPU, + GPU, + ACCELEARTOR, + ALL + } + public DeviceType getDeviceType() { + throw new UnsupportedOperationException("not supported yet"); + } + public int getVendorId() { + throw new UnsupportedOperationException("not supported yet"); + } + public boolean isAvailable() { + throw new UnsupportedOperationException("not supported yet"); + } + public int getPCIeBus() { + throw new UnsupportedOperationException("not supported yet"); + } + + public boolean hasCompiler() { + throw new UnsupportedOperationException("not supported yet"); + } + public boolean hasDouble() { + throw new UnsupportedOperationException("not supported yet"); + } + public boolean hasHalfFloat() { + throw new UnsupportedOperationException("not supported yet"); + } + public boolean hasErrorCorrectingMemory() { + throw new UnsupportedOperationException("not supported yet"); + } + public boolean hasUnifiedMemory() { + throw new UnsupportedOperationException("not supported yet"); + } + public boolean hasImageSupport() { + throw new UnsupportedOperationException("not supported yet"); + } + public boolean hasExtension(String extension) { + throw new UnsupportedOperationException("not supported yet"); + } + public Collection getExtensions() { + throw new UnsupportedOperationException("not supported yet"); + } + + public int getComputeUnits() { + throw new UnsupportedOperationException("not supported yet"); + } + public int getClockFrequency() { + throw new UnsupportedOperationException("not supported yet"); + } + public int getAddressBits() { + throw new UnsupportedOperationException("not supported yet"); + } + public boolean isLittleEndian() { + throw new UnsupportedOperationException("not supported yet"); + } + + public int getMaximumWorkItemDimensions() { + throw new UnsupportedOperationException("not supported yet"); + } + public int[] getMaximumWorkItemSizes() { + throw new UnsupportedOperationException("not supported yet"); + } + public int getMaxiumWorkItemsPerGroup() { + throw new UnsupportedOperationException("not supported yet"); + } + + public int getMaximumSamplers() { + throw new UnsupportedOperationException("not supported yet"); + } + public int getMaximumReadImages() { + throw new UnsupportedOperationException("not supported yet"); + } + public int getMaximumWriteImages() { + throw new UnsupportedOperationException("not supported yet"); + } + public int[] getMaximumImage2DSize() { + throw new UnsupportedOperationException("not supported yet"); + } + public int[] getMaximumImage3DSize() { + throw new UnsupportedOperationException("not supported yet"); + } + + //TODO: cache, prefered sizes properties + + public String getProfile() { + throw new UnsupportedOperationException("not supported yet"); + } + public String getVersion() { + throw new UnsupportedOperationException("not supported yet"); + } + public int getVersionMajor() { + throw new UnsupportedOperationException("not supported yet"); + } + public int getVersionMinor() { + throw new UnsupportedOperationException("not supported yet"); + } + public String getCompilerVersion() { + throw new UnsupportedOperationException("not supported yet"); + } + public int getCompilerVersionMajor() { + throw new UnsupportedOperationException("not supported yet"); + } + public int getCompilerVersionMinor() { + throw new UnsupportedOperationException("not supported yet"); + } + public String getDriverVersion() { + throw new UnsupportedOperationException("not supported yet"); + } + public int getDriverVersionMajor() { + throw new UnsupportedOperationException("not supported yet"); + } + public int getDriverVersionMinor() { + throw new UnsupportedOperationException("not supported yet"); + } + public String getName() { + throw new UnsupportedOperationException("not supported yet"); + } + public String getVendor() { + throw new UnsupportedOperationException("not supported yet"); + } + + @Override + public String toString() { + throw new UnsupportedOperationException("not supported yet"); + } +} diff --git a/jme3-core/src/main/java/com/jme3/opencl/KernelCompilationException.java b/jme3-core/src/main/java/com/jme3/opencl/KernelCompilationException.java new file mode 100644 index 000000000..37d7a07b7 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/KernelCompilationException.java @@ -0,0 +1,48 @@ +/* + * 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; + + +public class KernelCompilationException extends OpenCLException { + + private final String log; + + public KernelCompilationException(String msg, int errorCode, String log) { + super(msg, errorCode); + this.log = log; + } + + public String getLog() { + return log; + } + +} \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java b/jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java new file mode 100644 index 000000000..b0603b36a --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java @@ -0,0 +1,71 @@ +/* + * 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; + +/** + * + * @author Sebastian Weiss + */ +public class OpenCLException extends Exception { + + private final int errorCode; + + /** + * Creates a new instance of OpenCLExceptionn without detail + * message. + */ + public OpenCLException() { + errorCode = 0; + } + + /** + * Constructs an instance of OpenCLExceptionn 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; + } + + public int getErrorCode() { + return errorCode; + } + + +} From bb15931fa2c50ef16c1cd10efc7f2236478e15bc Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Mon, 18 Apr 2016 18:30:32 +0200 Subject: [PATCH 03/40] started with context creation --- .../src/main/java/com/jme3/opencl/CL.java | 229 +++++++------ .../java/com/jme3/opencl/CommandQueue.java | 199 ++++++----- .../main/java/com/jme3/opencl/Context.java | 259 ++++++++------- .../src/main/java/com/jme3/opencl/Kernel.java | 314 ++++++++++-------- .../java/com/jme3/opencl/NativeCLObject.java | 50 +++ .../java/com/jme3/system/AppSettings.java | 16 +- .../main/java/com/jme3/system/JmeContext.java | 5 + .../java/com/jme3/system/NullContext.java | 6 + .../com/jme3/system/awt/AwtPanelsContext.java | 6 + .../java/jme3test/gui/opencl/HelloOpenCL.java | 67 ++++ .../com/jme3/system/jogl/JoglContext.java | 17 + .../java/com/jme3/opencl/lwjgl/LwjglCL.java | 236 +++++++++++++ .../com/jme3/system/lwjgl/LwjglContext.java | 53 +++ .../com/jme3/system/lwjgl/LwjglDisplay.java | 4 + .../com/jme3/system/lwjgl/LwjglContext.java | 19 ++ 15 files changed, 1029 insertions(+), 451 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/opencl/NativeCLObject.java create mode 100644 jme3-examples/src/main/java/jme3test/gui/opencl/HelloOpenCL.java create mode 100644 jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCL.java diff --git a/jme3-core/src/main/java/com/jme3/opencl/CL.java b/jme3-core/src/main/java/com/jme3/opencl/CL.java index 71ae9d5b5..b7792ac49 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/CL.java +++ b/jme3-core/src/main/java/com/jme3/opencl/CL.java @@ -35,109 +35,136 @@ import java.nio.*; /** * Interface for OpenCL implementations + * * @author Sebastian Weiss */ public interface CL { - - //temp buffers for argument passing - public static class TempBuffer { - /** - * 16-Bytes (4 floats) of a byte buffer - */ - public final ByteBuffer b16; - /** - * Short-buffer view on b16 - */ - public final ShortBuffer b16s; - /** - * int buffer view on b16 - */ - public final IntBuffer b16i; - /** - * long buffer view on b16 - */ - public final LongBuffer b16l; - /** - * float buffer view on b16 - */ - public final FloatBuffer b16f; - /** - * double buffer view on b16 - */ - public final DoubleBuffer b16d; - - public TempBuffer(ByteBuffer b16) { - this.b16 = b16; - b16.rewind(); - this.b16s = b16.asShortBuffer(); - this.b16i = b16.asIntBuffer(); - this.b16l = b16.asLongBuffer(); - this.b16f = b16.asFloatBuffer(); - this.b16d = b16.asDoubleBuffer(); - } - } - /** - * Returns up to 4 temp buffer instances - * @return - */ - TempBuffer[] getTempBuffers(); - - //entry point - long getContext(); - - //OpenCL functions - long clCreateCommandQueue(long context, long device, boolean profiling); - void clReleaseCommandQueue(long queue); - - long clCreateBuffer(long context, MemoryAccess access, int size, ByteBuffer hostPtr); - long clEnqueueReadBuffer(long queue, long buffer, boolean blocking, int offset, int size, ByteBuffer ptr); - long clEnqueueWriteBuffer(long queue, long buffer, boolean blocking, int offset, int size, ByteBuffer ptr); - long clEnqueueCopyBuffer(long queue, long srcBuffer, long dstBuffer, int srcOffset, int dstOffset, int size); - long clEnqueueFillBuffer(long queue, long buffer, ByteBuffer pattern, int patternSize, int offset, int size); - long clEnqueueMapBuffer(long queue, long buffer, boolean blocking, MappingAccess flags, int offset, int size); - - long clCreateImage(long context, MemoryAccess access, Context.ImageFormat format, Context.ImageDescriptor desc, ByteBuffer ptr); - Context.ImageFormat[] clGetSupportedImageFormats(long context, MemoryAccess ma, Context.ImageType type); - - long clEnqueueReadImage(long queue, long image, boolean blocking, ByteBuffer origin, ByteBuffer region, int rowPitch, int slicePitch, ByteBuffer ptr); - long clEnqueueWriteImage(long queue, long image, boolean blocking, ByteBuffer origin, ByteBuffer region, int inputRowPitch, int intputSlicePitch, ByteBuffer ptr); - long clEnqueueCopyImage(long queue, long srcImage, long dstImage, ByteBuffer srcOrigin, ByteBuffer dstOrigin, ByteBuffer region); - long clEnqueueFillImage(long queue, long image, ByteBuffer fillColor, ByteBuffer origin, ByteBuffer region); - - long clEnqueueCopyImageToBuffer(long queue, long srcImage, long dstBuffer, ByteBuffer srcOrigin, ByteBuffer region, int dstOffset); - long clEnqueueCopyBufferToImage(long queue, long srcBuffer, long dstImage, int srcOffset, ByteBuffer dstOrigin, ByteBuffer region); - - long clEnqueueMapImage(long queue, long image, boolean blocking, MappingAccess ma, ByteBuffer origin, ByteBuffer region, int rowPitch, int slicePitch); + + //temp buffers for argument passing + public static class TempBuffer { + + /** + * 16-Bytes (4 floats) of a byte buffer + */ + public final ByteBuffer b16; + /** + * Short-buffer view on b16 + */ + public final ShortBuffer b16s; + /** + * int buffer view on b16 + */ + public final IntBuffer b16i; + /** + * long buffer view on b16 + */ + public final LongBuffer b16l; + /** + * float buffer view on b16 + */ + public final FloatBuffer b16f; + /** + * double buffer view on b16 + */ + public final DoubleBuffer b16d; + + public TempBuffer(ByteBuffer b16) { + this.b16 = b16; + b16.rewind(); + this.b16s = b16.asShortBuffer(); + this.b16i = b16.asIntBuffer(); + this.b16l = b16.asLongBuffer(); + this.b16f = b16.asFloatBuffer(); + this.b16d = b16.asDoubleBuffer(); + } + } + + /** + * Returns up to 4 temp buffer instances + * + * @return + */ + TempBuffer[] getTempBuffers(); + + //entry point + long getContext(); + + //OpenCL functions + long clCreateCommandQueue(long context, long device, boolean profiling); + + void clReleaseCommandQueue(long queue); + + long clCreateBuffer(long context, MemoryAccess access, int size, ByteBuffer hostPtr); + + long clEnqueueReadBuffer(long queue, long buffer, boolean blocking, int offset, int size, ByteBuffer ptr); + + long clEnqueueWriteBuffer(long queue, long buffer, boolean blocking, int offset, int size, ByteBuffer ptr); + + long clEnqueueCopyBuffer(long queue, long srcBuffer, long dstBuffer, int srcOffset, int dstOffset, int size); + + long clEnqueueFillBuffer(long queue, long buffer, ByteBuffer pattern, int patternSize, int offset, int size); + + long clEnqueueMapBuffer(long queue, long buffer, boolean blocking, MappingAccess flags, int offset, int size); + + long clCreateImage(long context, MemoryAccess access, Context.ImageFormat format, Context.ImageDescriptor desc, ByteBuffer ptr); + + Context.ImageFormat[] clGetSupportedImageFormats(long context, MemoryAccess ma, Context.ImageType type); + + long clEnqueueReadImage(long queue, long image, boolean blocking, ByteBuffer origin, ByteBuffer region, int rowPitch, int slicePitch, ByteBuffer ptr); + + long clEnqueueWriteImage(long queue, long image, boolean blocking, ByteBuffer origin, ByteBuffer region, int inputRowPitch, int intputSlicePitch, ByteBuffer ptr); + + long clEnqueueCopyImage(long queue, long srcImage, long dstImage, ByteBuffer srcOrigin, ByteBuffer dstOrigin, ByteBuffer region); + + long clEnqueueFillImage(long queue, long image, ByteBuffer fillColor, ByteBuffer origin, ByteBuffer region); + + long clEnqueueCopyImageToBuffer(long queue, long srcImage, long dstBuffer, ByteBuffer srcOrigin, ByteBuffer region, int dstOffset); + + long clEnqueueCopyBufferToImage(long queue, long srcBuffer, long dstImage, int srcOffset, ByteBuffer dstOrigin, ByteBuffer region); + + long clEnqueueMapImage(long queue, long image, boolean blocking, MappingAccess ma, ByteBuffer origin, ByteBuffer region, int rowPitch, int slicePitch); //TODO: clGetImageInfo - - void clReleaseMemObject(long mem); - long clEnqueueUnmapMemObject(long queue, long mem, ByteBuffer ptr); - int getMemSize(long mem); //uses clGetMemObjectInfo - - long clCreateProgramWithSource(long context, CharSequence[] sources); - //TODO: create from binary - long clReleaseProgram(long program); - - void clBuildProgram(long program, long[] devices, CharSequence optpions) throws KernelCompilationException; - String getKernelNames(long program); //uses clGetProgramInfo - - long clCreateKernel(long program, String kernelName); - void clReleaseKernel(long kernel); - void clSetKernelArg(long kernel, int argIndex, int argSize, ByteBuffer argValue); - String getKernelName(long kernel); //uses clGetKernelInfo - int getKernelNumArgs(long kernel); //uses clGetKernelInfo - //TODO: clGetKernelWorkGroupInfo - - long clEnqueueNDRangeKernel(long queue, long kernel, int workDim, - ByteBuffer globalWorkOffset, ByteBuffer globalWorkSize, ByteBuffer localWorkSize); - - void clWaitForEvents(long[] events); - void clWaitForEvent(long event); - boolean isEventCompleted(long event); //uses clGetEventInfo - void clReleaseEvent(long event); - - void clFlush(long queue); - void clFinish(long queue); - - + + void clReleaseMemObject(long mem); + + long clEnqueueUnmapMemObject(long queue, long mem, ByteBuffer ptr); + + int getMemSize(long mem); //uses clGetMemObjectInfo + + long clCreateProgramWithSource(long context, CharSequence[] sources); + + //TODO: create from binary + + long clReleaseProgram(long program); + + void clBuildProgram(long program, long[] devices, CharSequence optpions) throws KernelCompilationException; + + String getKernelNames(long program); //uses clGetProgramInfo + + long clCreateKernel(long program, String kernelName); + + void clReleaseKernel(long kernel); + + void clSetKernelArg(long kernel, int argIndex, int argSize, ByteBuffer argValue); + + String getKernelName(long kernel); //uses clGetKernelInfo + + int getKernelNumArgs(long kernel); //uses clGetKernelInfo + //TODO: clGetKernelWorkGroupInfo + + long clEnqueueNDRangeKernel(long queue, long kernel, int workDim, + ByteBuffer globalWorkOffset, ByteBuffer globalWorkSize, ByteBuffer localWorkSize); + + void clWaitForEvents(long[] events); + + void clWaitForEvent(long event); + + boolean isEventCompleted(long event); //uses clGetEventInfo + + void clReleaseEvent(long event); + + void clFlush(long queue); + + void clFinish(long queue); + } diff --git a/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java index 6354677fa..6d070143b 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java +++ b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java @@ -37,97 +37,116 @@ import java.nio.ByteBuffer; * * @author Sebastian Weiss */ -public final class CommandQueue { - private final long queue; - - public CommandQueue(long queue) { - this.queue = queue; - } - - public void read(Buffer src, ByteBuffer dest, int size, int offset) { - throw new UnsupportedOperationException("not supported yet"); - } - public void read(Buffer src, ByteBuffer dest, int size) { - read(src, dest, size, 0); - } - public void read(Buffer src, ByteBuffer dest) { - read(src, dest, src.getSize(), 0); - } - - public Event readAsync(Buffer src, ByteBuffer dest, int size, int offset) { - throw new UnsupportedOperationException("not supported yet"); - } - public Event readAsync(Buffer src, ByteBuffer dest, int size) { - return readAsync(src, dest, size, 0); - } - public Event readAsync(Buffer src, ByteBuffer dest) { - return readAsync(src, dest, src.getSize()); - } - - public void write(ByteBuffer src, Buffer dest, int size, int offset) { - throw new UnsupportedOperationException("not supported yet"); - } - public void write(ByteBuffer src, Buffer dest, int size) { - write(src, dest, size, 0); - } - public void write(ByteBuffer src, Buffer dest) { - write(src, dest, dest.getSize()); - } - - public Event writeAsync(ByteBuffer src, Buffer dest, int size, int offset) { - throw new UnsupportedOperationException("not supported yet"); - } - public Event writeAsync(ByteBuffer src, Buffer dest, int size) { - return writeAsync(src, dest, size, 0); - } - public Event writeAsync(ByteBuffer src, Buffer dest) { - return writeAsync(src, dest, dest.getSize()); - } - - public void copyTo(Buffer src, Buffer dest, int size, int srcOffset, int destOffset) { - throw new UnsupportedOperationException("not supported yet"); - } - public void copyTo(Buffer src, Buffer dest, int size) { - copyTo(src, dest, size, 0, 0); - } - public void copyTo(Buffer src, Buffer dest) { - copyTo(src, dest, src.getSize()); - } - - public Event copyToAsync(Buffer src, Buffer dest, int size, int srcOffset, int destOffset) { - throw new UnsupportedOperationException("not supported yet"); - } - public Event copyToAsync(Buffer src, Buffer dest, int size) { - return copyToAsync(src, dest, size, 0, 0); - } - public Event copyToAsync(Buffer src, Buffer dest) { - return copyToAsync(src, dest, src.getSize()); - } - - public ByteBuffer map(Buffer src, int size, int offset, MappingAccess access) { - throw new UnsupportedOperationException("not supported yet"); - } - public ByteBuffer map(Buffer src, int size, MappingAccess access) { - return map(src, size, 0, access); - } - public ByteBuffer map(Buffer src, MappingAccess access) { - return map(src, src.getSize(), access); - } - public void unmap(Buffer src, ByteBuffer ptr) { - throw new UnsupportedOperationException("not supported yet"); - } - +public final class CommandQueue extends NativeCLObject { + + private final long queue; + + public CommandQueue(long queue) { + this.queue = queue; + } + + public void read(Buffer src, ByteBuffer dest, int size, int offset) { + throw new UnsupportedOperationException("not supported yet"); + } + + public void read(Buffer src, ByteBuffer dest, int size) { + read(src, dest, size, 0); + } + + public void read(Buffer src, ByteBuffer dest) { + read(src, dest, src.getSize(), 0); + } + + public Event readAsync(Buffer src, ByteBuffer dest, int size, int offset) { + throw new UnsupportedOperationException("not supported yet"); + } + + public Event readAsync(Buffer src, ByteBuffer dest, int size) { + return readAsync(src, dest, size, 0); + } + + public Event readAsync(Buffer src, ByteBuffer dest) { + return readAsync(src, dest, src.getSize()); + } + + public void write(ByteBuffer src, Buffer dest, int size, int offset) { + throw new UnsupportedOperationException("not supported yet"); + } + + public void write(ByteBuffer src, Buffer dest, int size) { + write(src, dest, size, 0); + } + + public void write(ByteBuffer src, Buffer dest) { + write(src, dest, dest.getSize()); + } + + public Event writeAsync(ByteBuffer src, Buffer dest, int size, int offset) { + throw new UnsupportedOperationException("not supported yet"); + } + + public Event writeAsync(ByteBuffer src, Buffer dest, int size) { + return writeAsync(src, dest, size, 0); + } + + public Event writeAsync(ByteBuffer src, Buffer dest) { + return writeAsync(src, dest, dest.getSize()); + } + + public void copyTo(Buffer src, Buffer dest, int size, int srcOffset, int destOffset) { + throw new UnsupportedOperationException("not supported yet"); + } + + public void copyTo(Buffer src, Buffer dest, int size) { + copyTo(src, dest, size, 0, 0); + } + + public void copyTo(Buffer src, Buffer dest) { + copyTo(src, dest, src.getSize()); + } + + public Event copyToAsync(Buffer src, Buffer dest, int size, int srcOffset, int destOffset) { + throw new UnsupportedOperationException("not supported yet"); + } + + public Event copyToAsync(Buffer src, Buffer dest, int size) { + return copyToAsync(src, dest, size, 0, 0); + } + + public Event copyToAsync(Buffer src, Buffer dest) { + return copyToAsync(src, dest, src.getSize()); + } + + public ByteBuffer map(Buffer src, int size, int offset, MappingAccess access) { + throw new UnsupportedOperationException("not supported yet"); + } + + public ByteBuffer map(Buffer src, int size, MappingAccess access) { + return map(src, size, 0, access); + } + + public ByteBuffer map(Buffer src, MappingAccess access) { + return map(src, src.getSize(), access); + } + + public void unmap(Buffer src, ByteBuffer ptr) { + throw new UnsupportedOperationException("not supported yet"); + } + //TODO: async mapping - //TODO: clEnqueueFillBuffer - //TODO: image read/write - - public void flush() { - throw new UnsupportedOperationException("not supported yet"); - } - public void finish() { - throw new UnsupportedOperationException("not supported yet"); - } - + public void flush() { + throw new UnsupportedOperationException("not supported yet"); + } + + public void finish() { + throw new UnsupportedOperationException("not supported yet"); + } + + @Override + public void deleteObject() { + throw new UnsupportedOperationException("Not supported yet."); + } + } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index 4e3063fc9..4cd181d10 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -42,127 +42,150 @@ import java.util.List; /** * The central OpenCL context. Every actions start from here. + * * @author Sebastian Weiss */ -public final class Context { - - private final long context; - - public Context(long context) { - this.context = context; - } - - public List getDevices() { - throw new UnsupportedOperationException("not supported yet"); - } - - public CommandQueue createQueue() { - throw new UnsupportedOperationException("not supported yet"); - } +public final class Context extends NativeCLObject { + + private final long context; + + public Context(long context) { + this.context = context; + } + + public List getDevices() { + throw new UnsupportedOperationException("not supported yet"); + } + + public CommandQueue createQueue() { + throw new UnsupportedOperationException("not supported yet"); + } //TODO: constructor with specific device and properties - - public Buffer createBuffer(int size, MemoryAccess access) { - throw new UnsupportedOperationException("not supported yet"); - } - public Buffer createBuffer(int size) { - return createBuffer(size, MemoryAccess.READ_WRITE); - } - - public Buffer useHostBuffer(ByteBuffer data, int size, MemoryAccess access) { - throw new UnsupportedOperationException("not supported yet"); - } - public Buffer useHostBuffer(ByteBuffer data, int size) { - return useHostBuffer(data, size, MemoryAccess.READ_WRITE); - } - - public static enum ImageChannelOrder { - R, Rx, A, - INTENSITY, - LUMINANCE, - RG, RGx, RA, - RGB, RGBx, - RGBA, - ARGB, BGRA - } - public static enum ImageChannelType { - SNORM_INT8, - SNORM_INT16, - UNORM_INT8, - UNROM_INT16, - UNORM_SHORT_565, - UNROM_SHORT_555, - UNORM_INT_101010, - SIGNED_INT8, - SIGNED_INT16, - SIGNED_INT32, - UNSIGNED_INT8, - UNSIGNED_INT16, - UNSIGNED_INT32, - HALF_FLOAT, - FLOAT - } - public static class ImageFormat { //Struct - public ImageChannelOrder channelOrder; - public ImageChannelType channelType; - } - public static enum ImageType { - IMAGE_1D, - IMAGE_1D_BUFFER, - IMAGE_2D, - IMAGE_3D, - IMAGE_1D_ARRAY, - IMAGE_2D_ARRAY - } - public static class ImageDescriptor { //Struct - public ImageType type; - public int width; - public int height; - public int depth; - public int arraySize; - public int rowPitch; - public int slicePitch; - public int numMipLevels; - public int numSamples; - public Buffer buffer; - } - public Buffer createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr, ByteBuffer hostPtr) { - throw new UnsupportedOperationException("not supported yet"); - } + + public Buffer createBuffer(int size, MemoryAccess access) { + throw new UnsupportedOperationException("not supported yet"); + } + + public Buffer createBuffer(int size) { + return createBuffer(size, MemoryAccess.READ_WRITE); + } + + public Buffer useHostBuffer(ByteBuffer data, int size, MemoryAccess access) { + throw new UnsupportedOperationException("not supported yet"); + } + + public Buffer useHostBuffer(ByteBuffer data, int size) { + return useHostBuffer(data, size, MemoryAccess.READ_WRITE); + } + + @Override + public void deleteObject() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public static enum ImageChannelOrder { + + R, Rx, A, + INTENSITY, + LUMINANCE, + RG, RGx, RA, + RGB, RGBx, + RGBA, + ARGB, BGRA + } + + public static enum ImageChannelType { + + SNORM_INT8, + SNORM_INT16, + UNORM_INT8, + UNROM_INT16, + UNORM_SHORT_565, + UNROM_SHORT_555, + UNORM_INT_101010, + SIGNED_INT8, + SIGNED_INT16, + SIGNED_INT32, + UNSIGNED_INT8, + UNSIGNED_INT16, + UNSIGNED_INT32, + HALF_FLOAT, + FLOAT + } + + public static class ImageFormat { //Struct + + public ImageChannelOrder channelOrder; + public ImageChannelType channelType; + } + + public static enum ImageType { + + IMAGE_1D, + IMAGE_1D_BUFFER, + IMAGE_2D, + IMAGE_3D, + IMAGE_1D_ARRAY, + IMAGE_2D_ARRAY + } + + public static class ImageDescriptor { //Struct + + public ImageType type; + public int width; + public int height; + public int depth; + public int arraySize; + public int rowPitch; + public int slicePitch; + public int numMipLevels; + public int numSamples; + public Buffer buffer; + } + + public Buffer createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr, ByteBuffer hostPtr) { + throw new UnsupportedOperationException("not supported yet"); + } //TODO: add simplified methods for 1D, 2D, 3D textures - + //Interop - - public Buffer bindVertexBuffer(VertexBuffer vb) { - throw new UnsupportedOperationException("not supported yet"); - } - public Buffer bindIndexBuffer(IndexBuffer ib) { - if (!(ib instanceof IndexByteBuffer) - && !(ib instanceof IndexShortBuffer) - && !(ib instanceof IndexIntBuffer)) { - throw new IllegalArgumentException("Index buffer must be an IndexByteBuffer, IndexShortBuffer or IndexIntBuffer"); - } - throw new UnsupportedOperationException("not supported yet"); - } - public Buffer bindImage(Image image) { - throw new UnsupportedOperationException("not supported yet"); - } - - public Program createProgramFromSourceCode(String sourceCode) { - throw new UnsupportedOperationException("not supported yet"); - } - public Program createProgramFromSourceFilesWithInclude( - String include, String... resources) { - //TODO: load resources - throw new UnsupportedOperationException("not implemented yet"); - } - public Program createProgramFormSourcesWithInclude(String include, List resources) { - return createProgramFromSourceFilesWithInclude(include, resources.toArray(new String[resources.size()])); - } - public Program createProgramFromSources(String... resources) { - return createProgramFromSourceFilesWithInclude(null, resources); - } - public Program createProgramFromSources(List resources) { - return createProgramFormSourcesWithInclude(null, resources); - } - + public Buffer bindVertexBuffer(VertexBuffer vb) { + throw new UnsupportedOperationException("not supported yet"); + } + + public Buffer bindIndexBuffer(IndexBuffer ib) { + if (!(ib instanceof IndexByteBuffer) + && !(ib instanceof IndexShortBuffer) + && !(ib instanceof IndexIntBuffer)) { + throw new IllegalArgumentException("Index buffer must be an IndexByteBuffer, IndexShortBuffer or IndexIntBuffer"); + } + throw new UnsupportedOperationException("not supported yet"); + } + + public Buffer bindImage(Image image) { + throw new UnsupportedOperationException("not supported yet"); + } + + public Program createProgramFromSourceCode(String sourceCode) { + throw new UnsupportedOperationException("not supported yet"); + } + + public Program createProgramFromSourceFilesWithInclude( + String include, String... resources) { + //TODO: load resources + throw new UnsupportedOperationException("not implemented yet"); + } + + public Program createProgramFormSourcesWithInclude(String include, List resources) { + return createProgramFromSourceFilesWithInclude(include, resources.toArray(new String[resources.size()])); + } + + public Program createProgramFromSources(String... resources) { + return createProgramFromSourceFilesWithInclude(null, resources); + } + + public Program createProgramFromSources(List resources) { + return createProgramFormSourcesWithInclude(null, resources); + } + } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java index 4da0668f8..7716284ca 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java @@ -39,145 +39,177 @@ import com.jme3.math.Vector4f; * * @author Sebastian Weiss */ -public final class Kernel { - private final WorkSize globalWorkSize; - private final WorkSize workGroupSize; - private final long kernel; - - public Kernel(long kernel) { - this.kernel = kernel; - this.globalWorkSize = new WorkSize(0); - this.workGroupSize = new WorkSize(0); - } - - public String getName() { - throw new UnsupportedOperationException("not supported yet"); - } - public int getArgCount() { - throw new UnsupportedOperationException("not supported yet"); - } - - public WorkSize getGlobalWorkSize() { - return globalWorkSize; - } - public void setGlobalWorkSize(WorkSize ws) { - globalWorkSize.set(ws); - } - public void setGlobalWorkSize(int size) { - globalWorkSize.set(1, size); - } - public void setGlobalWorkSize(int width, int height) { - globalWorkSize.set(2, width, height); - } - public void setGlobalWorkSize(int width, int height, int depth) { - globalWorkSize.set(3, width, height, depth); - } - - public WorkSize getWorkGroupSize() { - return workGroupSize; - } - public void setWorkGroupSize(WorkSize ws) { - workGroupSize.set(ws); - } - public void setWorkGroupSize(int size) { - workGroupSize.set(1, size); - } - public void setWorkGroupSize(int width, int height) { - workGroupSize.set(2, width, height); - } - public void setWorkGroupSize(int width, int height, int depth) { - workGroupSize.set(3, width, height, depth); - } - public void setWorkGroupSizeToNull() { - workGroupSize.set(1, 0); - } - - public void setArg(int index, LocalMemPerElement t) { - throw new UnsupportedOperationException("not supported yet"); - } - public void setArg(int index, LocalMem t) { - throw new UnsupportedOperationException("not supported yet"); - } - public void setArg(int index, Buffer t) { - throw new UnsupportedOperationException("not supported yet"); - } - public void setArg(int index, byte b) { - throw new UnsupportedOperationException("not supported yet"); - } - public void setArg(int index, short s) { - throw new UnsupportedOperationException("not supported yet"); - } - public void setArg(int index, int i) { - throw new UnsupportedOperationException("not supported yet"); - } - public void setArg(int index, long l) { - throw new UnsupportedOperationException("not supported yet"); - } - public void setArg(int index, float f) { - throw new UnsupportedOperationException("not supported yet"); - } - public void setArg(int index, double d) { - throw new UnsupportedOperationException("not supported yet"); - } - public void setArg(int index, Vector2f v) { - throw new UnsupportedOperationException("not supported yet"); - } - //Vector3f not supported because cl_float3 is the same as a float4 - public void setArg(int index, Vector4f v) { - throw new UnsupportedOperationException("not supported yet"); - } - public void setArg(int index, Quaternion q) { - throw new UnsupportedOperationException("not supported yet"); - } - 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 LocalMemPerElement) { - setArg(index, (LocalMemPerElement) arg); - } else if (arg instanceof LocalMem) { - setArg(index, (LocalMem) arg); - } else if (arg instanceof Buffer) { - setArg(index, (Buffer) arg); - } else { - throw new IllegalArgumentException("unknown kernel argument type: "+arg); - } - } - private void setArgs(Object... args) { - for (int i=0; i { defaults.put("GammaCorrection", false); defaults.put("Resizable", false); defaults.put("SwapBuffers", true); - // defaults.put("Icons", null); + defaults.put("OpenCL", false); + // defaults.put("Icons", null); } /** @@ -1019,4 +1020,17 @@ public final class AppSettings extends HashMap { 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"); + } } diff --git a/jme3-core/src/main/java/com/jme3/system/JmeContext.java b/jme3-core/src/main/java/com/jme3/system/JmeContext.java index f4f47ae67..36aaa44a8 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeContext.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeContext.java @@ -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. */ diff --git a/jme3-core/src/main/java/com/jme3/system/NullContext.java b/jme3-core/src/main/java/com/jme3/system/NullContext.java index 54ee59c42..e7969c89e 100644 --- a/jme3-core/src/main/java/com/jme3/system/NullContext.java +++ b/jme3-core/src/main/java/com/jme3/system/NullContext.java @@ -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; + } } diff --git a/jme3-desktop/src/main/java/com/jme3/system/awt/AwtPanelsContext.java b/jme3-desktop/src/main/java/com/jme3/system/awt/AwtPanelsContext.java index 897632a00..ee41ea569 100644 --- a/jme3-desktop/src/main/java/com/jme3/system/awt/AwtPanelsContext.java +++ b/jme3-desktop/src/main/java/com/jme3/system/awt/AwtPanelsContext.java @@ -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(){ } diff --git a/jme3-examples/src/main/java/jme3test/gui/opencl/HelloOpenCL.java b/jme3-examples/src/main/java/jme3test/gui/opencl/HelloOpenCL.java new file mode 100644 index 000000000..66635420f --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/gui/opencl/HelloOpenCL.java @@ -0,0 +1,67 @@ +/* + * 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.gui.opencl; + +import jme3test.helloworld.*; +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; + +/** Sample 1 - how to get started with the most simple JME 3 application. + * Display a blue 3D cube and view from all sides by + * moving the mouse and pressing the WASD keys. */ +public class HelloOpenCL extends SimpleApplication { + + public static void main(String[] args){ + HelloOpenCL app = new HelloOpenCL(); + AppSettings settings = new AppSettings(true); + settings.setOpenCLSupport(true); + app.setSettings(settings); + app.start(); // start the game + } + + @Override + public void simpleInitApp() { + Box b = new Box(1, 1, 1); // create cube shape + Geometry 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 + } +} \ No newline at end of file diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java index 24a647ef6..602298bb9 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java @@ -35,6 +35,7 @@ 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.renderer.Renderer; import com.jme3.renderer.RendererException; import com.jme3.renderer.jogl.JoglGL; @@ -84,6 +85,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 +212,14 @@ public abstract class JoglContext implements JmeContext { if (joyInput != null) { joyInput.initialize(); } + + if (settings.isOpenCLSupport()) { + initOpenCL(); + } + } + + protected void initOpenCL() { + logger.info("Initialize OpenCL with JOGL"); } public void internalCreate() { @@ -266,4 +277,10 @@ public abstract class JoglContext implements JmeContext { } return samples; } + + @Override + public Context getOpenCLContext() { + return clContext; + } + } diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCL.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCL.java new file mode 100644 index 000000000..d1aa2a25b --- /dev/null +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCL.java @@ -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.Context; +import com.jme3.opencl.KernelCompilationException; +import com.jme3.opencl.MappingAccess; +import com.jme3.opencl.MemoryAccess; +import java.nio.ByteBuffer; + +/** + * + * @author Sebastian Weiss + */ +public class LwjglCL implements com.jme3.opencl.CL { + + @Override + public TempBuffer[] getTempBuffers() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long getContext() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clCreateCommandQueue(long context, long device, boolean profiling) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clReleaseCommandQueue(long queue) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clCreateBuffer(long context, MemoryAccess access, int size, ByteBuffer hostPtr) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clEnqueueReadBuffer(long queue, long buffer, boolean blocking, int offset, int size, ByteBuffer ptr) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clEnqueueWriteBuffer(long queue, long buffer, boolean blocking, int offset, int size, ByteBuffer ptr) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clEnqueueCopyBuffer(long queue, long srcBuffer, long dstBuffer, int srcOffset, int dstOffset, int size) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clEnqueueFillBuffer(long queue, long buffer, ByteBuffer pattern, int patternSize, int offset, int size) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clEnqueueMapBuffer(long queue, long buffer, boolean blocking, MappingAccess flags, int offset, int size) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clCreateImage(long context, MemoryAccess access, Context.ImageFormat format, Context.ImageDescriptor desc, ByteBuffer ptr) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Context.ImageFormat[] clGetSupportedImageFormats(long context, MemoryAccess ma, Context.ImageType type) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clEnqueueReadImage(long queue, long image, boolean blocking, ByteBuffer origin, ByteBuffer region, int rowPitch, int slicePitch, ByteBuffer ptr) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clEnqueueWriteImage(long queue, long image, boolean blocking, ByteBuffer origin, ByteBuffer region, int inputRowPitch, int intputSlicePitch, ByteBuffer ptr) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clEnqueueCopyImage(long queue, long srcImage, long dstImage, ByteBuffer srcOrigin, ByteBuffer dstOrigin, ByteBuffer region) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clEnqueueFillImage(long queue, long image, ByteBuffer fillColor, ByteBuffer origin, ByteBuffer region) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clEnqueueCopyImageToBuffer(long queue, long srcImage, long dstBuffer, ByteBuffer srcOrigin, ByteBuffer region, int dstOffset) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clEnqueueCopyBufferToImage(long queue, long srcBuffer, long dstImage, int srcOffset, ByteBuffer dstOrigin, ByteBuffer region) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clEnqueueMapImage(long queue, long image, boolean blocking, MappingAccess ma, ByteBuffer origin, ByteBuffer region, int rowPitch, int slicePitch) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clReleaseMemObject(long mem) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clEnqueueUnmapMemObject(long queue, long mem, ByteBuffer ptr) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getMemSize(long mem) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clCreateProgramWithSource(long context, CharSequence[] sources) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clReleaseProgram(long program) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clBuildProgram(long program, long[] devices, CharSequence optpions) throws KernelCompilationException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getKernelNames(long program) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clCreateKernel(long program, String kernelName) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clReleaseKernel(long kernel) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clSetKernelArg(long kernel, int argIndex, int argSize, ByteBuffer argValue) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getKernelName(long kernel) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getKernelNumArgs(long kernel) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public long clEnqueueNDRangeKernel(long queue, long kernel, int workDim, ByteBuffer globalWorkOffset, ByteBuffer globalWorkSize, ByteBuffer localWorkSize) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clWaitForEvents(long[] events) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clWaitForEvent(long event) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isEventCompleted(long event) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clReleaseEvent(long event) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clFlush(long queue) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void clFinish(long queue) { + throw new UnsupportedOperationException("Not supported yet."); + } + +} diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index be3014da5..e15688a43 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -35,6 +35,7 @@ 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.lwjgl.LwjglCL; import com.jme3.renderer.Renderer; import com.jme3.renderer.RendererException; import com.jme3.renderer.lwjgl.LwjglGL; @@ -54,12 +55,17 @@ 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.CL; +import org.lwjgl.opencl.CL10; +import org.lwjgl.opencl.CLPlatform; import org.lwjgl.opengl.*; /** @@ -81,6 +87,10 @@ public abstract class LwjglContext implements JmeContext { protected JInputJoyInput joyInput; protected Timer timer; protected SystemListener listener; + + protected LwjglCL clImpl; + protected CLPlatform clPlatform; + protected com.jme3.opencl.Context context; public void setSystemListener(SystemListener listener) { this.listener = listener; @@ -245,8 +255,47 @@ public abstract class LwjglContext implements JmeContext { if (joyInput != null) { joyInput.initialize(); } + } + 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; + } + + List platforms = CLPlatform.getPlatforms(); + StringBuilder platformInfos = new StringBuilder(); + platformInfos.append("Available OpenCL platforms:\n"); + ArrayList possiblePlatforms = new ArrayList(); + for (int i=0; i Date: Tue, 19 Apr 2016 07:24:53 +0200 Subject: [PATCH 04/40] listing and choosing devices --- .../com/jme3/system/lwjgl/LwjglContext.java | 49 +++++++++++++++++-- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index e15688a43..1a28eada3 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -35,6 +35,7 @@ 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.Context; import com.jme3.opencl.lwjgl.LwjglCL; import com.jme3.renderer.Renderer; import com.jme3.renderer.RendererException; @@ -63,9 +64,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.lwjgl.LWJGLException; import org.lwjgl.Sys; -import org.lwjgl.opencl.CL; -import org.lwjgl.opencl.CL10; -import org.lwjgl.opencl.CLPlatform; +import org.lwjgl.opencl.*; import org.lwjgl.opengl.*; /** @@ -90,7 +89,7 @@ public abstract class LwjglContext implements JmeContext { protected LwjglCL clImpl; protected CLPlatform clPlatform; - protected com.jme3.opencl.Context context; + protected com.jme3.opencl.Context clContext; public void setSystemListener(SystemListener listener) { this.listener = listener; @@ -268,6 +267,7 @@ public abstract class LwjglContext implements JmeContext { return; } + //load platforms List platforms = CLPlatform.getPlatforms(); StringBuilder platformInfos = new StringBuilder(); platformInfos.append("Available OpenCL platforms:\n"); @@ -282,6 +282,7 @@ public abstract class LwjglContext implements JmeContext { boolean supportsInterop = platform.getInfoString(CL10.CL_PLATFORM_EXTENSIONS).contains("cl_khr_gl_sharing"); platformInfos.append(" * Supports Interop: ").append(supportsInterop).append("\n"); if (supportsInterop) { + possiblePlatforms.add(i); } } @@ -291,9 +292,47 @@ public abstract class LwjglContext implements JmeContext { return; } int platformIndex = possiblePlatforms.get(0); + //TODO: add API to choose the platform logger.info("Choose platform with index "+(platformIndex+1)); + clPlatform = platforms.get(platformIndex); + //load devices + List devices = clPlatform.getDevices(CL10.CL_DEVICE_TYPE_GPU); + StringBuilder deviceInfos = new StringBuilder(); + deviceInfos.append("Available OpenCL devices:\n"); + ArrayList possibleDevices = new ArrayList(); + for (int i=0; i Date: Tue, 19 Apr 2016 15:51:20 +0200 Subject: [PATCH 05/40] added customizability of the platforms and devices by PlatformChooser --- .../src/main/java/com/jme3/opencl/Buffer.java | 106 ++----- .../src/main/java/com/jme3/opencl/CL.java | 1 + .../java/com/jme3/opencl/CommandQueue.java | 112 +------ .../main/java/com/jme3/opencl/Context.java | 96 ++---- .../src/main/java/com/jme3/opencl/Device.java | 164 +++------- .../{NativeCLObject.java => Image.java} | 14 +- .../src/main/java/com/jme3/opencl/Kernel.java | 5 +- .../main/java/com/jme3/opencl/Platform.java | 60 ++++ .../java/com/jme3/opencl/PlatformChooser.java | 54 ++++ .../java/com/jme3/system/AppSettings.java | 17 + .../com/jme3/opencl/lwjgl/LwjglContext.java | 136 ++++++++ .../com/jme3/opencl/lwjgl/LwjglDevice.java | 293 ++++++++++++++++++ .../com/jme3/opencl/lwjgl/LwjglPlatform.java | 127 ++++++++ .../opencl/lwjgl/PlatformChooserImpl.java | 92 ++++++ .../java/com/jme3/opencl/lwjgl/Utils.java | 51 +++ .../com/jme3/system/lwjgl/LwjglContext.java | 129 ++++---- 16 files changed, 1005 insertions(+), 452 deletions(-) rename jme3-core/src/main/java/com/jme3/opencl/{NativeCLObject.java => Image.java} (89%) create mode 100644 jme3-core/src/main/java/com/jme3/opencl/Platform.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/PlatformChooser.java create mode 100644 jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java create mode 100644 jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java create mode 100644 jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java create mode 100644 jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/PlatformChooserImpl.java create mode 100644 jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java diff --git a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java index ca1f86409..6cdf178c6 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java @@ -37,94 +37,40 @@ import java.nio.ByteBuffer; * * @author Sebastian Weiss */ -public class Buffer { +public interface Buffer { - private final long buffer; - - public Buffer(long buffer) { - this.buffer = buffer; - } - - public int getSize() { - throw new UnsupportedOperationException("not supported yet"); - } + int getSize(); - public MemoryAccess getMemoryAccessFlags() { - throw new UnsupportedOperationException("not supported yet"); - } + MemoryAccess getMemoryAccessFlags(); - public void read(CommandQueue queue, Buffer src, ByteBuffer dest, int size, int offset) { - queue.read(src, dest, size, offset); - } - public void read(CommandQueue queue, Buffer src, ByteBuffer dest, int size) { - queue.read(src, dest, size); - } - public void read(CommandQueue queue, Buffer src, ByteBuffer dest) { - queue.read(src, dest); - } + void read(CommandQueue queue, ByteBuffer dest, int size, int offset); + void read(CommandQueue queue, ByteBuffer dest, int size); + void read(CommandQueue queue, ByteBuffer dest); - public Event readAsync(CommandQueue queue, Buffer src, ByteBuffer dest, int size, int offset) { - return queue.readAsync(src, dest, size, offset); - } - public Event readAsync(CommandQueue queue, Buffer src, ByteBuffer dest, int size) { - return queue.readAsync(src, dest, size); - } - public Event readAsync(CommandQueue queue, Buffer src, ByteBuffer dest) { - return queue.readAsync(src, dest); - } + Event readAsync(CommandQueue queue, ByteBuffer dest, int size, int offset); + Event readAsync(CommandQueue queue, ByteBuffer dest, int size); + Event readAsync(CommandQueue queue, ByteBuffer dest); - public void write(CommandQueue queue, ByteBuffer src, Buffer dest, int size, int offset) { - queue.write(src, dest, size, offset); - } - public void write(CommandQueue queue, ByteBuffer src, Buffer dest, int size) { - queue.write(src, dest, size); - } - public void write(CommandQueue queue, ByteBuffer src, Buffer dest) { - queue.write(src, dest); - } + void write(CommandQueue queue, ByteBuffer src, int size, int offset); + void write(CommandQueue queue, ByteBuffer src, int size); + void write(CommandQueue queue, ByteBuffer src); - public Event writeAsync(CommandQueue queue, ByteBuffer src, Buffer dest, int size, int offset) { - return queue.writeAsync(src, dest, size, offset); - } - public Event writeAsync(CommandQueue queue, ByteBuffer src, Buffer dest, int size) { - return queue.writeAsync(src, dest, size); - } - public Event writeAsync(CommandQueue queue, ByteBuffer src, Buffer dest) { - return queue.writeAsync(src, dest); - } + Event writeAsync(CommandQueue queue, ByteBuffer src, int size, int offset); + Event writeAsync(CommandQueue queue, ByteBuffer src, int size); + Event writeAsync(CommandQueue queue, ByteBuffer src); - public void copyTo(CommandQueue queue, Buffer src, Buffer dest, int size, int srcOffset, int destOffset) { - queue.copyTo(src, dest, size, srcOffset, destOffset); - } - public void copyTo(CommandQueue queue, Buffer src, Buffer dest, int size) { - queue.copyTo(src, dest, size); - } - public void copyTo(CommandQueue queue, Buffer src, Buffer dest) { - queue.copyTo(src, dest); - } - - public Event copyToAsync(CommandQueue queue, Buffer src, Buffer dest, int size, int srcOffset, int destOffset) { - return queue.copyToAsync(src, dest, size, srcOffset, destOffset); - } - public Event copyToAsync(CommandQueue queue, Buffer src, Buffer dest, int size) { - return queue.copyToAsync(src, dest, size); - } - public Event copyToAsync(CommandQueue queue, Buffer src, Buffer dest) { - return queue.copyToAsync(src, dest); - } + void copyTo(CommandQueue queue, Buffer dest, int size, int srcOffset, int destOffset); + void copyTo(CommandQueue queue, Buffer dest, int size); + void copyTo(CommandQueue queue, Buffer dest); + + Event copyToAsync(CommandQueue queue, Buffer dest, int size, int srcOffset, int destOffset); + Event copyToAsync(CommandQueue queue, Buffer dest, int size); + Event copyToAsync(CommandQueue queue, Buffer dest); - public ByteBuffer map(CommandQueue queue, Buffer src, int size, int offset, MappingAccess access) { - return queue.map(src, size, offset, access); - } - public ByteBuffer map(CommandQueue queue, Buffer src, int size, MappingAccess access) { - return queue.map(src, size, access); - } - public ByteBuffer map(CommandQueue queue, Buffer src, MappingAccess access) { - return queue.map(src, access); - } - public void unmap(CommandQueue queue, Buffer src, ByteBuffer ptr) { - queue.unmap(src, ptr); - } + ByteBuffer map(CommandQueue queue, int size, int offset, MappingAccess access); + ByteBuffer map(CommandQueue queue, int size, MappingAccess access); + ByteBuffer map(CommandQueue queue, MappingAccess access); + void unmap(CommandQueue queue, ByteBuffer ptr); //TODO: async mapping diff --git a/jme3-core/src/main/java/com/jme3/opencl/CL.java b/jme3-core/src/main/java/com/jme3/opencl/CL.java index b7792ac49..8ae5dab11 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/CL.java +++ b/jme3-core/src/main/java/com/jme3/opencl/CL.java @@ -38,6 +38,7 @@ import java.nio.*; * * @author Sebastian Weiss */ +@Deprecated public interface CL { //temp buffers for argument passing diff --git a/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java index 6d070143b..a12e947e8 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java +++ b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java @@ -37,116 +37,10 @@ import java.nio.ByteBuffer; * * @author Sebastian Weiss */ -public final class CommandQueue extends NativeCLObject { +public interface CommandQueue { - private final long queue; + void flush(); - public CommandQueue(long queue) { - this.queue = queue; - } - - public void read(Buffer src, ByteBuffer dest, int size, int offset) { - throw new UnsupportedOperationException("not supported yet"); - } - - public void read(Buffer src, ByteBuffer dest, int size) { - read(src, dest, size, 0); - } - - public void read(Buffer src, ByteBuffer dest) { - read(src, dest, src.getSize(), 0); - } - - public Event readAsync(Buffer src, ByteBuffer dest, int size, int offset) { - throw new UnsupportedOperationException("not supported yet"); - } - - public Event readAsync(Buffer src, ByteBuffer dest, int size) { - return readAsync(src, dest, size, 0); - } - - public Event readAsync(Buffer src, ByteBuffer dest) { - return readAsync(src, dest, src.getSize()); - } - - public void write(ByteBuffer src, Buffer dest, int size, int offset) { - throw new UnsupportedOperationException("not supported yet"); - } - - public void write(ByteBuffer src, Buffer dest, int size) { - write(src, dest, size, 0); - } - - public void write(ByteBuffer src, Buffer dest) { - write(src, dest, dest.getSize()); - } - - public Event writeAsync(ByteBuffer src, Buffer dest, int size, int offset) { - throw new UnsupportedOperationException("not supported yet"); - } - - public Event writeAsync(ByteBuffer src, Buffer dest, int size) { - return writeAsync(src, dest, size, 0); - } - - public Event writeAsync(ByteBuffer src, Buffer dest) { - return writeAsync(src, dest, dest.getSize()); - } - - public void copyTo(Buffer src, Buffer dest, int size, int srcOffset, int destOffset) { - throw new UnsupportedOperationException("not supported yet"); - } - - public void copyTo(Buffer src, Buffer dest, int size) { - copyTo(src, dest, size, 0, 0); - } - - public void copyTo(Buffer src, Buffer dest) { - copyTo(src, dest, src.getSize()); - } - - public Event copyToAsync(Buffer src, Buffer dest, int size, int srcOffset, int destOffset) { - throw new UnsupportedOperationException("not supported yet"); - } - - public Event copyToAsync(Buffer src, Buffer dest, int size) { - return copyToAsync(src, dest, size, 0, 0); - } - - public Event copyToAsync(Buffer src, Buffer dest) { - return copyToAsync(src, dest, src.getSize()); - } - - public ByteBuffer map(Buffer src, int size, int offset, MappingAccess access) { - throw new UnsupportedOperationException("not supported yet"); - } - - public ByteBuffer map(Buffer src, int size, MappingAccess access) { - return map(src, size, 0, access); - } - - public ByteBuffer map(Buffer src, MappingAccess access) { - return map(src, src.getSize(), access); - } - - public void unmap(Buffer src, ByteBuffer ptr) { - throw new UnsupportedOperationException("not supported yet"); - } - - //TODO: async mapping - //TODO: clEnqueueFillBuffer - //TODO: image read/write - public void flush() { - throw new UnsupportedOperationException("not supported yet"); - } - - public void finish() { - throw new UnsupportedOperationException("not supported yet"); - } - - @Override - public void deleteObject() { - throw new UnsupportedOperationException("Not supported yet."); - } + void finish(); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index 4cd181d10..0201f696a 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -33,10 +33,6 @@ package com.jme3.opencl; import com.jme3.scene.VertexBuffer; import com.jme3.scene.mesh.IndexBuffer; -import com.jme3.scene.mesh.IndexByteBuffer; -import com.jme3.scene.mesh.IndexIntBuffer; -import com.jme3.scene.mesh.IndexShortBuffer; -import com.jme3.texture.Image; import java.nio.ByteBuffer; import java.util.List; @@ -45,43 +41,18 @@ import java.util.List; * * @author Sebastian Weiss */ -public final class Context extends NativeCLObject { +public interface Context { - private final long context; + List getDevices(); - public Context(long context) { - this.context = context; - } - - public List getDevices() { - throw new UnsupportedOperationException("not supported yet"); - } - - public CommandQueue createQueue() { - throw new UnsupportedOperationException("not supported yet"); - } - //TODO: constructor with specific device and properties + CommandQueue createQueue(); + CommandQueue createQueue(Device device); - public Buffer createBuffer(int size, MemoryAccess access) { - throw new UnsupportedOperationException("not supported yet"); - } + Buffer createBuffer(int size, MemoryAccess access); + Buffer createBuffer(int size); - public Buffer createBuffer(int size) { - return createBuffer(size, MemoryAccess.READ_WRITE); - } - - public Buffer useHostBuffer(ByteBuffer data, int size, MemoryAccess access) { - throw new UnsupportedOperationException("not supported yet"); - } - - public Buffer useHostBuffer(ByteBuffer data, int size) { - return useHostBuffer(data, size, MemoryAccess.READ_WRITE); - } - - @Override - public void deleteObject() { - throw new UnsupportedOperationException("Not supported yet."); - } + Buffer useHostBuffer(ByteBuffer data, int size, MemoryAccess access); + Buffer useHostBuffer(ByteBuffer data, int size); public static enum ImageChannelOrder { @@ -143,49 +114,18 @@ public final class Context extends NativeCLObject { public Buffer buffer; } - public Buffer createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr, ByteBuffer hostPtr) { - throw new UnsupportedOperationException("not supported yet"); - } + Image createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr, ByteBuffer hostPtr); //TODO: add simplified methods for 1D, 2D, 3D textures //Interop - public Buffer bindVertexBuffer(VertexBuffer vb) { - throw new UnsupportedOperationException("not supported yet"); - } - - public Buffer bindIndexBuffer(IndexBuffer ib) { - if (!(ib instanceof IndexByteBuffer) - && !(ib instanceof IndexShortBuffer) - && !(ib instanceof IndexIntBuffer)) { - throw new IllegalArgumentException("Index buffer must be an IndexByteBuffer, IndexShortBuffer or IndexIntBuffer"); - } - throw new UnsupportedOperationException("not supported yet"); - } - - public Buffer bindImage(Image image) { - throw new UnsupportedOperationException("not supported yet"); - } - - public Program createProgramFromSourceCode(String sourceCode) { - throw new UnsupportedOperationException("not supported yet"); - } - - public Program createProgramFromSourceFilesWithInclude( - String include, String... resources) { - //TODO: load resources - throw new UnsupportedOperationException("not implemented yet"); - } - - public Program createProgramFormSourcesWithInclude(String include, List resources) { - return createProgramFromSourceFilesWithInclude(include, resources.toArray(new String[resources.size()])); - } - - public Program createProgramFromSources(String... resources) { - return createProgramFromSourceFilesWithInclude(null, resources); - } - - public Program createProgramFromSources(List resources) { - return createProgramFormSourcesWithInclude(null, resources); - } + Buffer bindVertexBuffer(VertexBuffer vb); + Buffer bindIndexBuffer(IndexBuffer ib); + Image bindImage(com.jme3.texture.Image image); + + Program createProgramFromSourceCode(String sourceCode); + Program createProgramFromSourceFilesWithInclude(String include, String... resources); + Program createProgramFormSourcesWithInclude(String include, List resources); + Program createProgramFromSources(String... resources); + Program createProgramFromSources(List resources); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Device.java b/jme3-core/src/main/java/com/jme3/opencl/Device.java index 045b44ecb..5d9095b6f 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Device.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Device.java @@ -37,13 +37,10 @@ import java.util.Collection; * * @author Sebastian Weiss */ -public final class Device { - private final long device; - - public Device(long device) { - this.device = device; - } +public interface Device { + Platform getPlatform(); + public static enum DeviceType { DEFAULT, CPU, @@ -51,124 +48,55 @@ public final class Device { ACCELEARTOR, ALL } - public DeviceType getDeviceType() { - throw new UnsupportedOperationException("not supported yet"); - } - public int getVendorId() { - throw new UnsupportedOperationException("not supported yet"); - } - public boolean isAvailable() { - throw new UnsupportedOperationException("not supported yet"); - } - public int getPCIeBus() { - throw new UnsupportedOperationException("not supported yet"); - } + DeviceType getDeviceType(); + int getVendorId(); + boolean isAvailable(); - public boolean hasCompiler() { - throw new UnsupportedOperationException("not supported yet"); - } - public boolean hasDouble() { - throw new UnsupportedOperationException("not supported yet"); - } - public boolean hasHalfFloat() { - throw new UnsupportedOperationException("not supported yet"); - } - public boolean hasErrorCorrectingMemory() { - throw new UnsupportedOperationException("not supported yet"); - } - public boolean hasUnifiedMemory() { - throw new UnsupportedOperationException("not supported yet"); - } - public boolean hasImageSupport() { - throw new UnsupportedOperationException("not supported yet"); - } - public boolean hasExtension(String extension) { - throw new UnsupportedOperationException("not supported yet"); - } - public Collection getExtensions() { - throw new UnsupportedOperationException("not supported yet"); - } + boolean hasCompiler(); + boolean hasDouble(); + boolean hasHalfFloat(); + boolean hasErrorCorrectingMemory(); + boolean hasUnifiedMemory(); + boolean hasImageSupport(); + boolean hasWritableImage3D(); + boolean hasOpenGLInterop(); + boolean hasExtension(String extension); + Collection getExtensions(); - public int getComputeUnits() { - throw new UnsupportedOperationException("not supported yet"); - } - public int getClockFrequency() { - throw new UnsupportedOperationException("not supported yet"); - } - public int getAddressBits() { - throw new UnsupportedOperationException("not supported yet"); - } - public boolean isLittleEndian() { - throw new UnsupportedOperationException("not supported yet"); - } + int getComputeUnits(); + int getClockFrequency(); + int getAddressBits(); + boolean isLittleEndian(); - public int getMaximumWorkItemDimensions() { - throw new UnsupportedOperationException("not supported yet"); - } - public int[] getMaximumWorkItemSizes() { - throw new UnsupportedOperationException("not supported yet"); - } - public int getMaxiumWorkItemsPerGroup() { - throw new UnsupportedOperationException("not supported yet"); - } + long getMaximumWorkItemDimensions(); + long[] getMaximumWorkItemSizes(); + long getMaxiumWorkItemsPerGroup(); - public int getMaximumSamplers() { - throw new UnsupportedOperationException("not supported yet"); - } - public int getMaximumReadImages() { - throw new UnsupportedOperationException("not supported yet"); - } - public int getMaximumWriteImages() { - throw new UnsupportedOperationException("not supported yet"); - } - public int[] getMaximumImage2DSize() { - throw new UnsupportedOperationException("not supported yet"); - } - public int[] getMaximumImage3DSize() { - throw new UnsupportedOperationException("not supported yet"); - } + int getMaximumSamplers(); + int getMaximumReadImages(); + int getMaximumWriteImages(); + long[] getMaximumImage2DSize(); + long[] getMaximumImage3DSize(); + long getMaximumAllocationSize(); + long getGlobalMemorySize(); + long getLocalMemorySize(); + long getMaximumConstantBufferSize(); + int getMaximumConstantArguments(); + //TODO: cache, prefered sizes properties - public String getProfile() { - throw new UnsupportedOperationException("not supported yet"); - } - public String getVersion() { - throw new UnsupportedOperationException("not supported yet"); - } - public int getVersionMajor() { - throw new UnsupportedOperationException("not supported yet"); - } - public int getVersionMinor() { - throw new UnsupportedOperationException("not supported yet"); - } - public String getCompilerVersion() { - throw new UnsupportedOperationException("not supported yet"); - } - public int getCompilerVersionMajor() { - throw new UnsupportedOperationException("not supported yet"); - } - public int getCompilerVersionMinor() { - throw new UnsupportedOperationException("not supported yet"); - } - public String getDriverVersion() { - throw new UnsupportedOperationException("not supported yet"); - } - public int getDriverVersionMajor() { - throw new UnsupportedOperationException("not supported yet"); - } - public int getDriverVersionMinor() { - throw new UnsupportedOperationException("not supported yet"); - } - public String getName() { - throw new UnsupportedOperationException("not supported yet"); - } - public String getVendor() { - throw new UnsupportedOperationException("not supported yet"); - } + String getProfile(); + String getVersion(); + int getVersionMajor(); + int getVersionMinor(); + String getCompilerVersion(); + int getCompilerVersionMajor(); + int getCompilerVersionMinor(); + String getDriverVersion(); + int getDriverVersionMajor(); + int getDriverVersionMinor(); + String getName(); + String getVendor(); - @Override - public String toString() { - throw new UnsupportedOperationException("not supported yet"); - } } diff --git a/jme3-core/src/main/java/com/jme3/opencl/NativeCLObject.java b/jme3-core/src/main/java/com/jme3/opencl/Image.java similarity index 89% rename from jme3-core/src/main/java/com/jme3/opencl/NativeCLObject.java rename to jme3-core/src/main/java/com/jme3/opencl/Image.java index a4ac5a857..850dedd10 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/NativeCLObject.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Image.java @@ -35,16 +35,6 @@ package com.jme3.opencl; * * @author Sebastian Weiss */ -public abstract class NativeCLObject { - protected CL cl; - - public CL getCl() { - return cl; - } - - public void setCl(CL cl) { - this.cl = cl; - } - - public abstract void deleteObject(); +public interface Image { + } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java index 7716284ca..933b153ce 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java @@ -39,8 +39,8 @@ import com.jme3.math.Vector4f; * * @author Sebastian Weiss */ -public final class Kernel extends NativeCLObject { - +public final class Kernel { +/* private final WorkSize globalWorkSize; private final WorkSize workGroupSize; private final long kernel; @@ -212,4 +212,5 @@ public final class Kernel extends NativeCLObject { public void deleteObject() { throw new UnsupportedOperationException("Not supported yet."); } +*/ } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Platform.java b/jme3-core/src/main/java/com/jme3/opencl/Platform.java new file mode 100644 index 000000000..0d5b636ac --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/Platform.java @@ -0,0 +1,60 @@ +/* + * 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; + +/** + * + * @author Sebastian Weiss + */ +public interface Platform { + + List getDevices(); + + String getProfile(); + boolean isFullProfile(); + boolean isEmbeddedProfile(); + + String getVersion(); + int getVersionMajor(); + int getVersionMinor(); + + String getName(); + String getVendor(); + boolean hasOpenGLInterop(); + boolean hasExtension(String extension); + Collection getExtensions(); + + +} diff --git a/jme3-core/src/main/java/com/jme3/opencl/PlatformChooser.java b/jme3-core/src/main/java/com/jme3/opencl/PlatformChooser.java new file mode 100644 index 000000000..51453cbe5 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/PlatformChooser.java @@ -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 Sebastian Weiss + * @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 chooseDevices(List platforms); + +} diff --git a/jme3-core/src/main/java/com/jme3/system/AppSettings.java b/jme3-core/src/main/java/com/jme3/system/AppSettings.java index e77725bfc..991854ebf 100644 --- a/jme3-core/src/main/java/com/jme3/system/AppSettings.java +++ b/jme3-core/src/main/java/com/jme3/system/AppSettings.java @@ -31,6 +31,7 @@ */ package com.jme3.system; +import com.jme3.opencl.PlatformChooser; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -1033,4 +1034,20 @@ public final class AppSettings extends HashMap { 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: not set, an implementation defined one is used. + * + * @param chooser the class of the chooser, must have a default constructor + */ + public void setOpenCLPlatformChooser(Class chooser) { + putString("OpenCLPlatformChooser", chooser.getName()); + } + + public String getOpenCLPlatformChooser() { + return getString("OpenCLPlatformChooser"); + } } diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java new file mode 100644 index 000000000..e2d08e4d7 --- /dev/null +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java @@ -0,0 +1,136 @@ +/* + * 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.scene.VertexBuffer; +import com.jme3.scene.mesh.IndexBuffer; +import java.nio.ByteBuffer; +import java.util.List; +import org.lwjgl.opencl.CLContext; + +/** + * + * @author Sebastian Weiss + */ +public class LwjglContext implements Context { + private final CLContext context; + + public LwjglContext(CLContext context) { + this.context = context; + } + + public CLContext getContext() { + return context; + } + + @Override + public List getDevices() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CommandQueue createQueue() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CommandQueue createQueue(Device device) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Buffer createBuffer(int size, MemoryAccess access) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Buffer createBuffer(int size) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Buffer useHostBuffer(ByteBuffer data, int size, MemoryAccess access) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Buffer useHostBuffer(ByteBuffer data, int size) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Image createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr, ByteBuffer hostPtr) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Buffer bindVertexBuffer(VertexBuffer vb) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Buffer bindIndexBuffer(IndexBuffer ib) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Image bindImage(com.jme3.texture.Image image) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Program createProgramFromSourceCode(String sourceCode) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Program createProgramFromSourceFilesWithInclude(String include, String... resources) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Program createProgramFormSourcesWithInclude(String include, List resources) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Program createProgramFromSources(String... resources) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Program createProgramFromSources(List resources) { + throw new UnsupportedOperationException("Not supported yet."); + } + +} diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java new file mode 100644 index 000000000..b8985d6f5 --- /dev/null +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java @@ -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 Sebastian Weiss + */ +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 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(); + } + +} diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java new file mode 100644 index 000000000..67f7910be --- /dev/null +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java @@ -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 Sebastian Weiss + */ +public final class LwjglPlatform implements Platform { + + final CLPlatform platform; + List devices; + + public LwjglPlatform(CLPlatform platform) { + this.platform = platform; + } + + public CLPlatform getPlatform() { + return platform; + } + + @Override + public List 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 getExtensions() { + return Arrays.asList(platform.getInfoString(CL10.CL_PLATFORM_EXTENSIONS).split(" ")); + } + +} diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/PlatformChooserImpl.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/PlatformChooserImpl.java new file mode 100644 index 000000000..fd3a7147b --- /dev/null +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/PlatformChooserImpl.java @@ -0,0 +1,92 @@ +/* + * 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 com.jme3.opencl.PlatformChooser; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +/** + * + * @author Sebastian Weiss + */ +public class PlatformChooserImpl implements PlatformChooser { + private static final Logger LOG = Logger.getLogger(PlatformChooserImpl.class.getName()); + + @Override + public List chooseDevices(List platforms) { + ArrayList result = new ArrayList(); + 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 + } + +} diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java new file mode 100644 index 000000000..985d60ad3 --- /dev/null +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java @@ -0,0 +1,51 @@ +/* + * 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; + +/** + * + * @author Sebastian Weiss + */ +public class 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); + } +} diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index 1a28eada3..02bdd281a 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -36,7 +36,12 @@ import com.jme3.input.lwjgl.JInputJoyInput; import com.jme3.input.lwjgl.LwjglKeyInput; import com.jme3.input.lwjgl.LwjglMouseInput; import com.jme3.opencl.Context; +import com.jme3.opencl.Device; +import com.jme3.opencl.PlatformChooser; import com.jme3.opencl.lwjgl.LwjglCL; +import com.jme3.opencl.lwjgl.LwjglDevice; +import com.jme3.opencl.lwjgl.LwjglPlatform; +import com.jme3.opencl.lwjgl.PlatformChooserImpl; import com.jme3.renderer.Renderer; import com.jme3.renderer.RendererException; import com.jme3.renderer.lwjgl.LwjglGL; @@ -87,9 +92,8 @@ public abstract class LwjglContext implements JmeContext { protected Timer timer; protected SystemListener listener; - protected LwjglCL clImpl; - protected CLPlatform clPlatform; - protected com.jme3.opencl.Context clContext; + protected LwjglPlatform clPlatform; + protected com.jme3.opencl.lwjgl.LwjglContext clContext; public void setSystemListener(SystemListener listener) { this.listener = listener; @@ -267,70 +271,89 @@ public abstract class LwjglContext implements JmeContext { return; } - //load platforms - List platforms = CLPlatform.getPlatforms(); + //load platforms and devices StringBuilder platformInfos = new StringBuilder(); - platformInfos.append("Available OpenCL platforms:\n"); - ArrayList possiblePlatforms = new ArrayList(); + ArrayList platforms = new ArrayList<>(); + for (CLPlatform p : CLPlatform.getPlatforms()) { + platforms.add(new LwjglPlatform(p)); + } + platformInfos.append("Available OpenCL platforms:"); for (int i=0; i devices = platform.getDevices(); + platformInfos.append("\n * Available devices:"); + for (int j=0; j devices = clPlatform.getDevices(CL10.CL_DEVICE_TYPE_GPU); - StringBuilder deviceInfos = new StringBuilder(); - deviceInfos.append("Available OpenCL devices:\n"); - ArrayList possibleDevices = new ArrayList(); - for (int i=0; i choosenDevices = chooser.chooseDevices(platforms); + List 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 - CLContext context; try { - context = CLContext.create(clPlatform, possibleDevices, null, Display.getDrawable(), null); + clContext = new com.jme3.opencl.lwjgl.LwjglContext(CLContext.create(platform.getPlatform(), devices, null, Display.getDrawable(), null)); } catch (LWJGLException ex) { logger.log(Level.SEVERE, "Unable to create OpenCL context", ex); return; } - clContext = new Context(context.getPointer()); - - //create cl implementation - clImpl = new LwjglCL(); - clContext.setCl(clImpl); logger.info("OpenCL context created"); } From e469af2ebcb1bb9c01a45be7e63e1ba474075d73 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Wed, 20 Apr 2016 09:50:21 +0200 Subject: [PATCH 06/40] implemented LwjglCommandQueue, LwjglBuffer and LwjglEvent, added buffer test to HelloOpenCL --- .../main/java/com/jme3/opencl/Context.java | 4 +- .../src/main/java/com/jme3/opencl/Event.java | 15 +- .../src/main/java/com/jme3/opencl/Kernel.java | 79 ++---- .../java/com/jme3/opencl/OpenCLException.java | 2 +- .../main/java/com/jme3/opencl/Program.java | 19 +- .../java/jme3test/gui/opencl/HelloOpenCL.java | 99 +++++++- .../com/jme3/opencl/lwjgl/LwjglBuffer.java | 220 ++++++++++++++++ .../java/com/jme3/opencl/lwjgl/LwjglCL.java | 236 ------------------ .../jme3/opencl/lwjgl/LwjglCommandQueue.java | 66 +++++ .../com/jme3/opencl/lwjgl/LwjglContext.java | 39 ++- .../com/jme3/opencl/lwjgl/LwjglEvent.java | 71 ++++++ .../java/com/jme3/opencl/lwjgl/Utils.java | 77 ++++++ .../com/jme3/system/lwjgl/LwjglContext.java | 6 +- 13 files changed, 581 insertions(+), 352 deletions(-) create mode 100644 jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java delete mode 100644 jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCL.java create mode 100644 jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java create mode 100644 jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index 0201f696a..8877b5823 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -51,8 +51,8 @@ public interface Context { Buffer createBuffer(int size, MemoryAccess access); Buffer createBuffer(int size); - Buffer useHostBuffer(ByteBuffer data, int size, MemoryAccess access); - Buffer useHostBuffer(ByteBuffer data, int size); + Buffer createBufferFromHost(ByteBuffer data, MemoryAccess access); + Buffer createBufferFromHost(ByteBuffer data); public static enum ImageChannelOrder { diff --git a/jme3-core/src/main/java/com/jme3/opencl/Event.java b/jme3-core/src/main/java/com/jme3/opencl/Event.java index ec08d764b..501df2593 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Event.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Event.java @@ -35,18 +35,9 @@ package com.jme3.opencl; * * @author Sebastian Weiss */ -public final class Event { - private final long event; - - public Event(long event) { - this.event = event; - } +public interface Event { - public void waitForFinished() { - throw new UnsupportedOperationException("not supported yet"); - } + void waitForFinished(); - public boolean isCompleted() { - throw new UnsupportedOperationException("not supported yet"); - } + boolean isCompleted(); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java index 933b153ce..813da8ced 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java @@ -34,30 +34,24 @@ package com.jme3.opencl; import com.jme3.math.Quaternion; import com.jme3.math.Vector2f; import com.jme3.math.Vector4f; +import java.nio.ByteBuffer; /** * * @author Sebastian Weiss */ -public final class Kernel { -/* +public abstract class Kernel { private final WorkSize globalWorkSize; private final WorkSize workGroupSize; - private final long kernel; - public Kernel(long kernel) { - this.kernel = kernel; + protected Kernel() { this.globalWorkSize = new WorkSize(0); this.workGroupSize = new WorkSize(0); } - public String getName() { - throw new UnsupportedOperationException("not supported yet"); - } + public abstract String getName(); - public int getArgCount() { - throw new UnsupportedOperationException("not supported yet"); - } + public abstract int getArgCount(); public WorkSize getGlobalWorkSize() { return globalWorkSize; @@ -103,55 +97,31 @@ public final class Kernel { workGroupSize.set(1, 0); } - public void setArg(int index, LocalMemPerElement t) { - throw new UnsupportedOperationException("not supported yet"); - } + public abstract void setArg(int index, LocalMemPerElement t); - public void setArg(int index, LocalMem t) { - throw new UnsupportedOperationException("not supported yet"); - } + public abstract void setArg(int index, LocalMem t); - public void setArg(int index, Buffer t) { - throw new UnsupportedOperationException("not supported yet"); - } + public abstract void setArg(int index, Buffer t); - public void setArg(int index, byte b) { - throw new UnsupportedOperationException("not supported yet"); - } + public abstract void setArg(int index, byte b); - public void setArg(int index, short s) { - throw new UnsupportedOperationException("not supported yet"); - } + public abstract void setArg(int index, short s); - public void setArg(int index, int i) { - throw new UnsupportedOperationException("not supported yet"); - } + public abstract void setArg(int index, int i); - public void setArg(int index, long l) { - throw new UnsupportedOperationException("not supported yet"); - } + public abstract void setArg(int index, long l); - public void setArg(int index, float f) { - throw new UnsupportedOperationException("not supported yet"); - } + public abstract void setArg(int index, float f); - public void setArg(int index, double d) { - throw new UnsupportedOperationException("not supported yet"); - } + public abstract void setArg(int index, double d); - public void setArg(int index, Vector2f v) { - throw new UnsupportedOperationException("not supported yet"); - } + public abstract void setArg(int index, Vector2f v); + + public abstract void setArg(int index, Vector4f v); - //Vector3f not supported because cl_float3 is the same as a float4 - - public void setArg(int index, Vector4f v) { - throw new UnsupportedOperationException("not supported yet"); - } - - public void setArg(int index, Quaternion q) { - throw new UnsupportedOperationException("not supported yet"); - } + public abstract void setArg(int index, Quaternion q); + + public abstract void setArg(int index, ByteBuffer buffer, long size); public void setArg(int index, Object arg) { if (arg instanceof Byte) { @@ -189,9 +159,7 @@ public final class Kernel { } } - public Event Run(CommandQueue queue) { - throw new UnsupportedOperationException("not supported yet"); - } + public abstract Event Run(CommandQueue queue); public Event Run1(CommandQueue queue, WorkSize globalWorkSize, Object... args) { setGlobalWorkSize(globalWorkSize); @@ -208,9 +176,4 @@ public final class Kernel { return Run(queue); } - @Override - public void deleteObject() { - throw new UnsupportedOperationException("Not supported yet."); - } -*/ } diff --git a/jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java b/jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java index b0603b36a..5cfe47a9a 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java +++ b/jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java @@ -35,7 +35,7 @@ package com.jme3.opencl; * * @author Sebastian Weiss */ -public class OpenCLException extends Exception { +public class OpenCLException extends RuntimeException { private final int errorCode; diff --git a/jme3-core/src/main/java/com/jme3/opencl/Program.java b/jme3-core/src/main/java/com/jme3/opencl/Program.java index 74c5d5662..32c594a04 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Program.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Program.java @@ -35,22 +35,11 @@ package com.jme3.opencl; * * @author Sebastian Weiss */ -public final class Program { - private final long program; - - public Program(long program) { - this.program = program; - } +public interface Program { - public void build(String args) { - throw new UnsupportedOperationException("not supported yet"); - } - public void build() { - build(null); - } + void build(String args) throws KernelCompilationException; + void build() throws KernelCompilationException; - public Kernel createKernel(String name) { - throw new UnsupportedOperationException("not supported yet"); - } + Kernel createKernel(String name); } diff --git a/jme3-examples/src/main/java/jme3test/gui/opencl/HelloOpenCL.java b/jme3-examples/src/main/java/jme3test/gui/opencl/HelloOpenCL.java index 66635420f..d653c0934 100644 --- a/jme3-examples/src/main/java/jme3test/gui/opencl/HelloOpenCL.java +++ b/jme3-examples/src/main/java/jme3test/gui/opencl/HelloOpenCL.java @@ -32,19 +32,24 @@ package jme3test.gui.opencl; -import jme3test.helloworld.*; import com.jme3.app.SimpleApplication; -import com.jme3.material.Material; -import com.jme3.math.ColorRGBA; -import com.jme3.math.Vector3f; -import com.jme3.scene.Geometry; -import com.jme3.scene.shape.Box; +import com.jme3.font.BitmapFont; +import com.jme3.font.BitmapText; +import com.jme3.opencl.Buffer; +import com.jme3.opencl.CommandQueue; +import com.jme3.opencl.Context; +import com.jme3.opencl.Event; import com.jme3.system.AppSettings; +import com.jme3.util.BufferUtils; +import java.nio.ByteBuffer; +import java.util.logging.Level; +import java.util.logging.Logger; /** Sample 1 - how to get started with the most simple JME 3 application. * Display a blue 3D cube and view from all sides by * moving the mouse and pressing the WASD keys. */ 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(); @@ -56,12 +61,80 @@ public class HelloOpenCL extends SimpleApplication { @Override public void simpleInitApp() { - Box b = new Box(1, 1, 1); // create cube shape - Geometry 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 + 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)); + + BitmapText txt1 = new BitmapText(fnt); + txt1.setText(str.toString()); + txt1.setLocalTranslation(5, settings.getHeight() - 5, 0); + guiNode.attachChild(txt1); + } + + 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(); + if (b != (byte)i) { + System.err.println("Wrong byte read: expected="+i+", actual="+b); + return false; + } + } + + //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 devices; - public LwjglContext(CLContext context) { + public LwjglContext(CLContext context, List devices) { this.context = context; + this.devices = devices; } public CLContext getContext() { @@ -55,37 +57,50 @@ public class LwjglContext implements Context { @Override public List getDevices() { - throw new UnsupportedOperationException("Not supported yet."); + return devices; } @Override public CommandQueue createQueue() { - throw new UnsupportedOperationException("Not supported yet."); + return createQueue(devices.get(0)); } @Override + @SuppressWarnings("element-type-mismatch") public CommandQueue createQueue(Device device) { - throw new UnsupportedOperationException("Not supported yet."); + 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(int size, MemoryAccess access) { - throw new UnsupportedOperationException("Not supported yet."); + long flags = Utils.getMemoryAccessFlags(access); + CLMem mem = CL10.clCreateBuffer(context, flags, (long) size, Utils.errorBuffer); + Utils.checkError(Utils.errorBuffer, "clCreateBuffer"); + return new LwjglBuffer(mem); } @Override public Buffer createBuffer(int size) { - throw new UnsupportedOperationException("Not supported yet."); + return createBuffer(size, MemoryAccess.READ_WRITE); } @Override - public Buffer useHostBuffer(ByteBuffer data, int size, MemoryAccess access) { - throw new UnsupportedOperationException("Not supported yet."); + 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 Buffer useHostBuffer(ByteBuffer data, int size) { - throw new UnsupportedOperationException("Not supported yet."); + public Buffer createBufferFromHost(ByteBuffer data) { + return createBufferFromHost(data, MemoryAccess.READ_WRITE); } @Override diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java new file mode 100644 index 000000000..ebe0ca458 --- /dev/null +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java @@ -0,0 +1,71 @@ +/* + * 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 org.lwjgl.opencl.CL10; +import org.lwjgl.opencl.CLEvent; + +/** + * + * @author Sebastian Weiss + */ +public class LwjglEvent implements Event { + private final CLEvent event; + + public LwjglEvent(CLEvent event) { + this.event = event; + } + + public CLEvent getEvent() { + return event; + } + + @Override + public void waitForFinished() { + CL10.clWaitForEvents(event); + } + + @Override + public boolean isCompleted() { + int status = event.getInfoInt(CL10.CL_EVENT_COMMAND_EXECUTION_STATUS); + if (status == CL10.CL_SUCCESS) { + return true; + } else if (status < 0) { + Utils.checkError(status, "EventStatus"); + return false; + } else { + return false; + } + } + +} diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java index 985d60ad3..89509c0ec 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java @@ -31,6 +31,17 @@ */ package com.jme3.opencl.lwjgl; +import com.jme3.opencl.MappingAccess; +import com.jme3.opencl.MemoryAccess; +import com.jme3.opencl.OpenCLException; +import java.nio.*; +import org.lwjgl.BufferUtils; +import org.lwjgl.LWJGLUtil; +import org.lwjgl.PointerBuffer; +import org.lwjgl.opencl.CL10; +import org.lwjgl.opencl.CL12; +import org.lwjgl.opencl.Util; + /** * * @author Sebastian Weiss @@ -48,4 +59,70 @@ public class Utils { 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 TempBuffer[] tempBuffers = new TempBuffer[8]; + public static 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); + } + + 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) { + //TODO: proper handling + Util.checkCLError(error); + } + + 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); + } + } } diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index 02bdd281a..32767fa9b 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -35,10 +35,8 @@ 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.Context; import com.jme3.opencl.Device; import com.jme3.opencl.PlatformChooser; -import com.jme3.opencl.lwjgl.LwjglCL; import com.jme3.opencl.lwjgl.LwjglDevice; import com.jme3.opencl.lwjgl.LwjglPlatform; import com.jme3.opencl.lwjgl.PlatformChooserImpl; @@ -261,6 +259,7 @@ public abstract class LwjglContext implements JmeContext { } + @SuppressWarnings("unchecked") protected void initOpenCL() { logger.info("Initialize OpenCL wiht LWJGL2"); @@ -349,7 +348,8 @@ public abstract class LwjglContext implements JmeContext { //create context try { - clContext = new com.jme3.opencl.lwjgl.LwjglContext(CLContext.create(platform.getPlatform(), devices, null, Display.getDrawable(), null)); + CLContext c = CLContext.create(platform.getPlatform(), devices, null, Display.getDrawable(), null); + clContext = new com.jme3.opencl.lwjgl.LwjglContext(c, (List) choosenDevices); } catch (LWJGLException ex) { logger.log(Level.SEVERE, "Unable to create OpenCL context", ex); return; From 6326daa120abd2a5620fda2e483809a9a772d202 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Thu, 21 Apr 2016 08:31:31 +0200 Subject: [PATCH 07/40] implemented program building --- .../main/java/com/jme3/opencl/Context.java | 9 +- .../main/java/com/jme3/opencl/Program.java | 3 +- .../{gui => }/opencl/HelloOpenCL.java | 21 ++- .../main/resources/jme3test/opencl/Blas.cl | 4 + .../com/jme3/opencl/lwjgl/LwjglContext.java | 55 +++++-- .../com/jme3/opencl/lwjgl/LwjglKernel.java | 138 ++++++++++++++++++ .../com/jme3/opencl/lwjgl/LwjglProgram.java | 111 ++++++++++++++ 7 files changed, 321 insertions(+), 20 deletions(-) rename jme3-examples/src/main/java/jme3test/{gui => }/opencl/HelloOpenCL.java (87%) create mode 100644 jme3-examples/src/main/resources/jme3test/opencl/Blas.cl create mode 100644 jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java create mode 100644 jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index 8877b5823..0be677e30 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -31,6 +31,7 @@ */ package com.jme3.opencl; +import com.jme3.asset.AssetManager; import com.jme3.scene.VertexBuffer; import com.jme3.scene.mesh.IndexBuffer; import java.nio.ByteBuffer; @@ -123,9 +124,9 @@ public interface Context { Image bindImage(com.jme3.texture.Image image); Program createProgramFromSourceCode(String sourceCode); - Program createProgramFromSourceFilesWithInclude(String include, String... resources); - Program createProgramFormSourcesWithInclude(String include, List resources); - Program createProgramFromSources(String... resources); - Program createProgramFromSources(List resources); + Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, String... resources); + Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, List resources); + Program createProgramFromSourceFiles(AssetManager assetManager, String... resources); + Program createProgramFromSourceFiles(AssetManager assetManager, List resources); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Program.java b/jme3-core/src/main/java/com/jme3/opencl/Program.java index 32c594a04..36203264a 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Program.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Program.java @@ -41,5 +41,6 @@ public interface Program { void build() throws KernelCompilationException; Kernel createKernel(String name); - + Kernel[] createAllKernels(); + } diff --git a/jme3-examples/src/main/java/jme3test/gui/opencl/HelloOpenCL.java b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java similarity index 87% rename from jme3-examples/src/main/java/jme3test/gui/opencl/HelloOpenCL.java rename to jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java index d653c0934..3ac75b824 100644 --- a/jme3-examples/src/main/java/jme3test/gui/opencl/HelloOpenCL.java +++ b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java @@ -30,15 +30,12 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jme3test.gui.opencl; +package jme3test.opencl; import com.jme3.app.SimpleApplication; import com.jme3.font.BitmapFont; import com.jme3.font.BitmapText; -import com.jme3.opencl.Buffer; -import com.jme3.opencl.CommandQueue; -import com.jme3.opencl.Context; -import com.jme3.opencl.Event; +import com.jme3.opencl.*; import com.jme3.system.AppSettings; import com.jme3.util.BufferUtils; import java.nio.ByteBuffer; @@ -78,6 +75,7 @@ public class HelloOpenCL extends SimpleApplication { .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)); BitmapText txt1 = new BitmapText(fnt); txt1.setText(str.toString()); @@ -137,4 +135,17 @@ public class HelloOpenCL extends SimpleApplication { } return true; } + + private boolean testKernel(Context clContext, CommandQueue clQueue) { + String include = "#define TYPE float\n"; + Program program = clContext.createProgramFromSourceFilesWithInclude(assetManager, include, "jme3test/opencl/Blas.cl"); + program.build(); + Kernel[] kernels = program.createAllKernels(); + for (Kernel k : kernels) { + System.out.println("available kernel: "+k.getName()); + } + Kernel kernel = program.createKernel("Fill"); + System.out.println("number of args: "+kernel.getArgCount()); + return true; + } } \ No newline at end of file diff --git a/jme3-examples/src/main/resources/jme3test/opencl/Blas.cl b/jme3-examples/src/main/resources/jme3test/opencl/Blas.cl new file mode 100644 index 000000000..a39569258 --- /dev/null +++ b/jme3-examples/src/main/resources/jme3test/opencl/Blas.cl @@ -0,0 +1,4 @@ +__kernel void Fill (__global TYPE* data, TYPE a) +{ + data[get_global_id(0)] = a; +} \ No newline at end of file diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java index 08321d502..4d7e3be57 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java @@ -31,18 +31,29 @@ */ package com.jme3.opencl.lwjgl; +import com.jme3.asset.AssetInfo; +import com.jme3.asset.AssetKey; +import com.jme3.asset.AssetManager; import com.jme3.opencl.*; import com.jme3.scene.VertexBuffer; import com.jme3.scene.mesh.IndexBuffer; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; import java.nio.ByteBuffer; +import java.util.Arrays; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import org.lwjgl.opencl.*; +import sun.misc.IOUtils; /** * * @author Sebastian Weiss */ public class LwjglContext implements Context { + private static final Logger LOG = Logger.getLogger(LwjglContext.class.getName()); private final CLContext context; private final List devices; @@ -56,7 +67,7 @@ public class LwjglContext implements Context { } @Override - public List getDevices() { + public List getDevices() { return devices; } @@ -125,27 +136,51 @@ public class LwjglContext implements Context { @Override public Program createProgramFromSourceCode(String sourceCode) { - throw new UnsupportedOperationException("Not supported yet."); + LOG.log(Level.INFO, "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 createProgramFromSourceFilesWithInclude(String include, String... resources) { - throw new UnsupportedOperationException("Not supported yet."); + public Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, String... resources) { + return createProgramFromSourceFilesWithInclude(assetManager, include, Arrays.asList(resources)); } @Override - public Program createProgramFormSourcesWithInclude(String include, List resources) { - throw new UnsupportedOperationException("Not supported yet."); + public Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, List resources) { + StringBuilder str = new StringBuilder(); + str.append(include); + for (String res : resources) { + AssetInfo info = assetManager.locateAsset(new AssetKey(res)); + if (info == null) { + LOG.log(Level.WARNING, "unable to load source file ''{0}''", res); + continue; + } + 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 createProgramFromSourceCode(str.toString()); } @Override - public Program createProgramFromSources(String... resources) { - throw new UnsupportedOperationException("Not supported yet."); + public Program createProgramFromSourceFiles(AssetManager assetManager, String... resources) { + return createProgramFromSourceFilesWithInclude(assetManager, "", resources); } @Override - public Program createProgramFromSources(List resources) { - throw new UnsupportedOperationException("Not supported yet."); + public Program createProgramFromSourceFiles(AssetManager assetManager, List resources) { + return createProgramFromSourceFilesWithInclude(assetManager, "", resources); } } diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java new file mode 100644 index 000000000..4b962a3f7 --- /dev/null +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java @@ -0,0 +1,138 @@ +/* + * 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.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector4f; +import com.jme3.opencl.*; +import java.nio.ByteBuffer; +import org.lwjgl.opencl.CL10; +import org.lwjgl.opencl.CLKernel; + +/** + * + * @author Sebastian Weiss + */ +public class LwjglKernel extends Kernel { + + private final CLKernel kernel; + + public LwjglKernel(CLKernel 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 void setArg(int index, LocalMemPerElement t) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setArg(int index, LocalMem t) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setArg(int index, Buffer t) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setArg(int index, byte b) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setArg(int index, short s) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setArg(int index, int i) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setArg(int index, long l) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setArg(int index, float f) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setArg(int index, double d) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setArg(int index, Vector2f v) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setArg(int index, Vector4f v) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setArg(int index, Quaternion q) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setArg(int index, ByteBuffer buffer, long size) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Event Run(CommandQueue queue) { + throw new UnsupportedOperationException("Not supported yet."); + } + +} diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java new file mode 100644 index 000000000..a3239e5fd --- /dev/null +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java @@ -0,0 +1,111 @@ +/* + * 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.Kernel; +import com.jme3.opencl.KernelCompilationException; +import com.jme3.opencl.Program; +import java.util.ArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.lwjgl.PointerBuffer; +import org.lwjgl.opencl.*; + +/** + * + * @author Sebastian Weiss + */ +public class LwjglProgram implements 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) { + this.program = program; + this.context = context; + } + + public CLProgram getProgram() { + return program; + } + + @Override + public void build(String args) throws KernelCompilationException { + int ret = CL10.clBuildProgram(program, (PointerBuffer) null, 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()); + } + } + + @Override + public void build() throws KernelCompilationException { + build(""); + } + + 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 Date: Thu, 21 Apr 2016 09:04:04 +0200 Subject: [PATCH 08/40] implemented kernel execution --- .../src/main/java/com/jme3/opencl/Kernel.java | 6 +- .../main/java/com/jme3/opencl/WorkSize.java | 14 +-- .../java/jme3test/opencl/HelloOpenCL.java | 44 ++++++-- .../com/jme3/opencl/lwjgl/LwjglKernel.java | 105 +++++++++++++++--- 4 files changed, 136 insertions(+), 33 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java index 813da8ced..913a867d1 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java @@ -41,8 +41,8 @@ import java.nio.ByteBuffer; * @author Sebastian Weiss */ public abstract class Kernel { - private final WorkSize globalWorkSize; - private final WorkSize workGroupSize; + protected final WorkSize globalWorkSize; + protected final WorkSize workGroupSize; protected Kernel() { this.globalWorkSize = new WorkSize(0); @@ -94,7 +94,7 @@ public abstract class Kernel { } public void setWorkGroupSizeToNull() { - workGroupSize.set(1, 0); + workGroupSize.set(1, 0, 0, 0); } public abstract void setArg(int index, LocalMemPerElement t); diff --git a/jme3-core/src/main/java/com/jme3/opencl/WorkSize.java b/jme3-core/src/main/java/com/jme3/opencl/WorkSize.java index b16ad99bf..9a923a42f 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/WorkSize.java +++ b/jme3-core/src/main/java/com/jme3/opencl/WorkSize.java @@ -39,9 +39,9 @@ import java.util.Arrays; */ public final class WorkSize { private int dimension; - private int[] sizes; + private long[] sizes; - public WorkSize(int dimension, int... sizes) + public WorkSize(int dimension, long... sizes) { set(dimension, sizes); } @@ -49,24 +49,24 @@ public final class WorkSize { public WorkSize() { this(1, 1, 1, 1); } - public WorkSize(int size) { + public WorkSize(long size) { this(1, size, 1, 1); } - public WorkSize(int width, int height) { + public WorkSize(long width, long height) { this(2, width, height, 1); } - public WorkSize(int width, int height, int depth) { + public WorkSize(long width, long height, long depth) { this(3, width, height, depth); } public int getDimension() { return dimension; } - public int[] getSizes() { + public long[] getSizes() { return sizes; } - public void set(int dimension, int... 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"); } diff --git a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java index 3ac75b824..50d032102 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java +++ b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java @@ -39,6 +39,7 @@ 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.logging.Level; import java.util.logging.Logger; @@ -137,15 +138,42 @@ public class HelloOpenCL extends SimpleApplication { } private boolean testKernel(Context clContext, CommandQueue clQueue) { - String include = "#define TYPE float\n"; - Program program = clContext.createProgramFromSourceFilesWithInclude(assetManager, include, "jme3test/opencl/Blas.cl"); - program.build(); - Kernel[] kernels = program.createAllKernels(); - for (Kernel k : kernels) { - System.out.println("available kernel: "+k.getName()); + try { + //create fill code + String include = "#define TYPE float\n"; + Program program = clContext.createProgramFromSourceFilesWithInclude(assetManager, include, "jme3test/opencl/Blas.cl"); + program.build(); + Kernel[] kernels = program.createAllKernels(); + for (Kernel k : kernels) { + System.out.println("available kernel: "+k.getName()); + } + 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 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 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))); } } From a6be243db1654e6fa6781a0047f10ee6f94eaac8 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Thu, 21 Apr 2016 15:05:55 +0200 Subject: [PATCH 09/40] refactoring of Context: moved simplifying functions from LwjglContext to Context --- .../main/java/com/jme3/opencl/Context.java | 80 +++++++++++++++---- .../java/jme3test/opencl/HelloOpenCL.java | 1 + .../com/jme3/opencl/lwjgl/LwjglContext.java | 57 +------------ 3 files changed, 65 insertions(+), 73 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index 0be677e30..68df8c807 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -31,29 +31,44 @@ */ package com.jme3.opencl; +import com.jme3.asset.AssetInfo; +import com.jme3.asset.AssetKey; import com.jme3.asset.AssetManager; import com.jme3.scene.VertexBuffer; import com.jme3.scene.mesh.IndexBuffer; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; 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 actions start from here. * * @author Sebastian Weiss */ -public interface Context { +public abstract class Context { + private static final Logger LOG = Logger.getLogger(Context.class.getName()); - List getDevices(); + public abstract List getDevices(); - CommandQueue createQueue(); - CommandQueue createQueue(Device device); + public CommandQueue createQueue() { + return createQueue(getDevices().get(0)); + } + public abstract CommandQueue createQueue(Device device); - Buffer createBuffer(int size, MemoryAccess access); - Buffer createBuffer(int size); + public abstract Buffer createBuffer(int size, MemoryAccess access); + public Buffer createBuffer(int size) { + return createBuffer(size, MemoryAccess.READ_WRITE); + } - Buffer createBufferFromHost(ByteBuffer data, MemoryAccess access); - Buffer createBufferFromHost(ByteBuffer data); + public abstract Buffer createBufferFromHost(ByteBuffer data, MemoryAccess access); + public Buffer createBufferFromHost(ByteBuffer data) { + return createBufferFromHost(data, MemoryAccess.READ_WRITE); + } public static enum ImageChannelOrder { @@ -115,18 +130,49 @@ public interface Context { public Buffer buffer; } - Image createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr, ByteBuffer hostPtr); + public abstract Image createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr, ByteBuffer hostPtr); //TODO: add simplified methods for 1D, 2D, 3D textures //Interop - Buffer bindVertexBuffer(VertexBuffer vb); - Buffer bindIndexBuffer(IndexBuffer ib); - Image bindImage(com.jme3.texture.Image image); + public abstract Buffer bindVertexBuffer(VertexBuffer vb); + public abstract Buffer bindIndexBuffer(IndexBuffer ib); + public abstract Image bindImage(com.jme3.texture.Image image); + + public abstract Program createProgramFromSourceCode(String sourceCode); + + public Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, String... resources) { + return createProgramFromSourceFilesWithInclude(assetManager, include, Arrays.asList(resources)); + } - Program createProgramFromSourceCode(String sourceCode); - Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, String... resources); - Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, List resources); - Program createProgramFromSourceFiles(AssetManager assetManager, String... resources); - Program createProgramFromSourceFiles(AssetManager assetManager, List resources); + public Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, List resources) { + StringBuilder str = new StringBuilder(); + str.append(include); + for (String res : resources) { + AssetInfo info = assetManager.locateAsset(new AssetKey(res)); + if (info == null) { + LOG.log(Level.WARNING, "unable to load source file ''{0}''", res); + continue; + } + 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 createProgramFromSourceCode(str.toString()); + } + + public Program createProgramFromSourceFiles(AssetManager assetManager, String... resources) { + return createProgramFromSourceFilesWithInclude(assetManager, "", resources); + } + public Program createProgramFromSourceFiles(AssetManager assetManager, List resources) { + return createProgramFromSourceFilesWithInclude(assetManager, "", resources); + } } diff --git a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java index 50d032102..a5459c6b0 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java +++ b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java @@ -53,6 +53,7 @@ public class HelloOpenCL extends SimpleApplication { HelloOpenCL app = new HelloOpenCL(); AppSettings settings = new AppSettings(true); settings.setOpenCLSupport(true); + settings.setVSync(true); app.setSettings(settings); app.start(); // start the game } diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java index 4d7e3be57..bd8c771fe 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java @@ -52,7 +52,7 @@ import sun.misc.IOUtils; * * @author Sebastian Weiss */ -public class LwjglContext implements Context { +public class LwjglContext extends Context { private static final Logger LOG = Logger.getLogger(LwjglContext.class.getName()); private final CLContext context; private final List devices; @@ -71,11 +71,6 @@ public class LwjglContext implements Context { return devices; } - @Override - public CommandQueue createQueue() { - return createQueue(devices.get(0)); - } - @Override @SuppressWarnings("element-type-mismatch") public CommandQueue createQueue(Device device) { @@ -95,11 +90,6 @@ public class LwjglContext implements Context { return new LwjglBuffer(mem); } - @Override - public Buffer createBuffer(int size) { - return createBuffer(size, MemoryAccess.READ_WRITE); - } - @Override public Buffer createBufferFromHost(ByteBuffer data, MemoryAccess access) { long flags = Utils.getMemoryAccessFlags(access); @@ -109,11 +99,6 @@ public class LwjglContext implements Context { return new LwjglBuffer(mem); } - @Override - public Buffer createBufferFromHost(ByteBuffer data) { - return createBufferFromHost(data, MemoryAccess.READ_WRITE); - } - @Override public Image createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr, ByteBuffer hostPtr) { throw new UnsupportedOperationException("Not supported yet."); @@ -142,45 +127,5 @@ public class LwjglContext implements Context { Utils.checkError(Utils.errorBuffer, "clCreateProgramWithSource"); return new LwjglProgram(p, this); } - - @Override - public Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, String... resources) { - return createProgramFromSourceFilesWithInclude(assetManager, include, Arrays.asList(resources)); - } - - @Override - public Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, List resources) { - StringBuilder str = new StringBuilder(); - str.append(include); - for (String res : resources) { - AssetInfo info = assetManager.locateAsset(new AssetKey(res)); - if (info == null) { - LOG.log(Level.WARNING, "unable to load source file ''{0}''", res); - continue; - } - 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 createProgramFromSourceCode(str.toString()); - } - - @Override - public Program createProgramFromSourceFiles(AssetManager assetManager, String... resources) { - return createProgramFromSourceFilesWithInclude(assetManager, "", resources); - } - - @Override - public Program createProgramFromSourceFiles(AssetManager assetManager, List resources) { - return createProgramFromSourceFilesWithInclude(assetManager, "", resources); - } } From 4416295069b81c4f020c17acc960c68a77cfc51e Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Fri, 22 Apr 2016 08:48:37 +0200 Subject: [PATCH 10/40] started with the image api, refactored buffer --- .../src/main/java/com/jme3/opencl/Buffer.java | 157 ++++++-- .../src/main/java/com/jme3/opencl/CL.java | 171 --------- .../main/java/com/jme3/opencl/Context.java | 66 +--- .../src/main/java/com/jme3/opencl/Image.java | 196 ++++++++++ .../src/main/java/com/jme3/opencl/Kernel.java | 2 + .../java/jme3test/opencl/HelloOpenCL.java | 81 +++- .../com/jme3/opencl/lwjgl/LwjglBuffer.java | 112 ++---- .../com/jme3/opencl/lwjgl/LwjglContext.java | 51 ++- .../com/jme3/opencl/lwjgl/LwjglImage.java | 351 ++++++++++++++++++ .../com/jme3/opencl/lwjgl/LwjglKernel.java | 6 + .../java/com/jme3/opencl/lwjgl/Utils.java | 8 +- 11 files changed, 839 insertions(+), 362 deletions(-) delete mode 100644 jme3-core/src/main/java/com/jme3/opencl/CL.java create mode 100644 jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java diff --git a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java index 6cdf178c6..8db068dfa 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java @@ -37,44 +37,121 @@ import java.nio.ByteBuffer; * * @author Sebastian Weiss */ -public interface Buffer { - - int getSize(); - - MemoryAccess getMemoryAccessFlags(); - - void read(CommandQueue queue, ByteBuffer dest, int size, int offset); - void read(CommandQueue queue, ByteBuffer dest, int size); - void read(CommandQueue queue, ByteBuffer dest); - - Event readAsync(CommandQueue queue, ByteBuffer dest, int size, int offset); - Event readAsync(CommandQueue queue, ByteBuffer dest, int size); - Event readAsync(CommandQueue queue, ByteBuffer dest); - - void write(CommandQueue queue, ByteBuffer src, int size, int offset); - void write(CommandQueue queue, ByteBuffer src, int size); - void write(CommandQueue queue, ByteBuffer src); - - Event writeAsync(CommandQueue queue, ByteBuffer src, int size, int offset); - Event writeAsync(CommandQueue queue, ByteBuffer src, int size); - Event writeAsync(CommandQueue queue, ByteBuffer src); - - void copyTo(CommandQueue queue, Buffer dest, int size, int srcOffset, int destOffset); - void copyTo(CommandQueue queue, Buffer dest, int size); - void copyTo(CommandQueue queue, Buffer dest); - - Event copyToAsync(CommandQueue queue, Buffer dest, int size, int srcOffset, int destOffset); - Event copyToAsync(CommandQueue queue, Buffer dest, int size); - Event copyToAsync(CommandQueue queue, Buffer dest); - - ByteBuffer map(CommandQueue queue, int size, int offset, MappingAccess access); - ByteBuffer map(CommandQueue queue, int size, MappingAccess access); - ByteBuffer map(CommandQueue queue, MappingAccess access); - void unmap(CommandQueue queue, ByteBuffer ptr); - - //TODO: async mapping - - //TODO: clEnqueueFillBuffer - - //TODO: image read/write +public abstract class Buffer { + + public abstract int getSize(); + + public abstract MemoryAccess getMemoryAccessFlags(); + + public abstract void read(CommandQueue queue, ByteBuffer dest, int size, int offset); + + public void read(CommandQueue queue, ByteBuffer dest, int size) { + read(queue, dest, size, 0); + } + + public void read(CommandQueue queue, ByteBuffer dest) { + read(queue, dest, getSize()); + } + + public abstract Event readAsync(CommandQueue queue, ByteBuffer dest, int size, int offset); + + public Event readAsync(CommandQueue queue, ByteBuffer dest, int size) { + return readAsync(queue, dest, size, 0); + } + + public Event readAsync(CommandQueue queue, ByteBuffer dest) { + return readAsync(queue, dest, getSize()); + } + + public abstract void write(CommandQueue queue, ByteBuffer src, int size, int offset); + + public void write(CommandQueue queue, ByteBuffer src, int size) { + write(queue, src, size, 0); + } + + public void write(CommandQueue queue, ByteBuffer src) { + write(queue, src, getSize()); + } + + public abstract Event writeAsync(CommandQueue queue, ByteBuffer src, int size, int offset); + + public Event writeAsync(CommandQueue queue, ByteBuffer src, int size) { + return writeAsync(queue, src, size, 0); + } + + public Event writeAsync(CommandQueue queue, ByteBuffer src) { + return writeAsync(queue, src, getSize()); + } + + public abstract void copyTo(CommandQueue queue, Buffer dest, int size, int srcOffset, int destOffset); + + public void copyTo(CommandQueue queue, Buffer dest, int size) { + copyTo(queue, dest, size, 0, 0); + } + + public void copyTo(CommandQueue queue, Buffer dest) { + copyTo(queue, dest, getSize()); + } + + public abstract Event copyToAsync(CommandQueue queue, Buffer dest, int size, int srcOffset, int destOffset); + + public Event copyToAsync(CommandQueue queue, Buffer dest, int size) { + return copyToAsync(queue, dest, size, 0, 0); + } + + public Event copyToAsync(CommandQueue queue, Buffer dest) { + return copyToAsync(queue, dest, getSize()); + } + + public abstract ByteBuffer map(CommandQueue queue, int size, int offset, MappingAccess access); + + public ByteBuffer map(CommandQueue queue, int size, MappingAccess access) { + return map(queue, size, 0, access); + } + + public ByteBuffer map(CommandQueue queue, MappingAccess access) { + return map(queue, getSize(), access); + } + + public abstract void unmap(CommandQueue queue, ByteBuffer ptr); + + public abstract AsyncMapping mapAsync(CommandQueue queue, int size, int offset, MappingAccess access); + public AsyncMapping mapAsync(CommandQueue queue, int size, MappingAccess access) { + return mapAsync(queue, size, 0, access); + } + public AsyncMapping mapAsync(CommandQueue queue, MappingAccess access) { + return mapAsync(queue, getSize(), 0, access); + } + + public abstract Event fillAsync(CommandQueue queue, ByteBuffer pattern, int size, int offset); + + //TODO: copy to image + + /** + * 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 Sebastian Weiss + */ + 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; + } + + public Event getEvent() { + return event; + } + + public ByteBuffer getBuffer() { + return buffer; + } + } + + public abstract Event copyToImageAsync(CommandQueue queue, Image dest, long srcOffset, long[] destOrigin, long[] destRegion); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/CL.java b/jme3-core/src/main/java/com/jme3/opencl/CL.java deleted file mode 100644 index 8ae5dab11..000000000 --- a/jme3-core/src/main/java/com/jme3/opencl/CL.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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.*; - -/** - * Interface for OpenCL implementations - * - * @author Sebastian Weiss - */ -@Deprecated -public interface CL { - - //temp buffers for argument passing - public static class TempBuffer { - - /** - * 16-Bytes (4 floats) of a byte buffer - */ - public final ByteBuffer b16; - /** - * Short-buffer view on b16 - */ - public final ShortBuffer b16s; - /** - * int buffer view on b16 - */ - public final IntBuffer b16i; - /** - * long buffer view on b16 - */ - public final LongBuffer b16l; - /** - * float buffer view on b16 - */ - public final FloatBuffer b16f; - /** - * double buffer view on b16 - */ - public final DoubleBuffer b16d; - - public TempBuffer(ByteBuffer b16) { - this.b16 = b16; - b16.rewind(); - this.b16s = b16.asShortBuffer(); - this.b16i = b16.asIntBuffer(); - this.b16l = b16.asLongBuffer(); - this.b16f = b16.asFloatBuffer(); - this.b16d = b16.asDoubleBuffer(); - } - } - - /** - * Returns up to 4 temp buffer instances - * - * @return - */ - TempBuffer[] getTempBuffers(); - - //entry point - long getContext(); - - //OpenCL functions - long clCreateCommandQueue(long context, long device, boolean profiling); - - void clReleaseCommandQueue(long queue); - - long clCreateBuffer(long context, MemoryAccess access, int size, ByteBuffer hostPtr); - - long clEnqueueReadBuffer(long queue, long buffer, boolean blocking, int offset, int size, ByteBuffer ptr); - - long clEnqueueWriteBuffer(long queue, long buffer, boolean blocking, int offset, int size, ByteBuffer ptr); - - long clEnqueueCopyBuffer(long queue, long srcBuffer, long dstBuffer, int srcOffset, int dstOffset, int size); - - long clEnqueueFillBuffer(long queue, long buffer, ByteBuffer pattern, int patternSize, int offset, int size); - - long clEnqueueMapBuffer(long queue, long buffer, boolean blocking, MappingAccess flags, int offset, int size); - - long clCreateImage(long context, MemoryAccess access, Context.ImageFormat format, Context.ImageDescriptor desc, ByteBuffer ptr); - - Context.ImageFormat[] clGetSupportedImageFormats(long context, MemoryAccess ma, Context.ImageType type); - - long clEnqueueReadImage(long queue, long image, boolean blocking, ByteBuffer origin, ByteBuffer region, int rowPitch, int slicePitch, ByteBuffer ptr); - - long clEnqueueWriteImage(long queue, long image, boolean blocking, ByteBuffer origin, ByteBuffer region, int inputRowPitch, int intputSlicePitch, ByteBuffer ptr); - - long clEnqueueCopyImage(long queue, long srcImage, long dstImage, ByteBuffer srcOrigin, ByteBuffer dstOrigin, ByteBuffer region); - - long clEnqueueFillImage(long queue, long image, ByteBuffer fillColor, ByteBuffer origin, ByteBuffer region); - - long clEnqueueCopyImageToBuffer(long queue, long srcImage, long dstBuffer, ByteBuffer srcOrigin, ByteBuffer region, int dstOffset); - - long clEnqueueCopyBufferToImage(long queue, long srcBuffer, long dstImage, int srcOffset, ByteBuffer dstOrigin, ByteBuffer region); - - long clEnqueueMapImage(long queue, long image, boolean blocking, MappingAccess ma, ByteBuffer origin, ByteBuffer region, int rowPitch, int slicePitch); - //TODO: clGetImageInfo - - void clReleaseMemObject(long mem); - - long clEnqueueUnmapMemObject(long queue, long mem, ByteBuffer ptr); - - int getMemSize(long mem); //uses clGetMemObjectInfo - - long clCreateProgramWithSource(long context, CharSequence[] sources); - - //TODO: create from binary - - long clReleaseProgram(long program); - - void clBuildProgram(long program, long[] devices, CharSequence optpions) throws KernelCompilationException; - - String getKernelNames(long program); //uses clGetProgramInfo - - long clCreateKernel(long program, String kernelName); - - void clReleaseKernel(long kernel); - - void clSetKernelArg(long kernel, int argIndex, int argSize, ByteBuffer argValue); - - String getKernelName(long kernel); //uses clGetKernelInfo - - int getKernelNumArgs(long kernel); //uses clGetKernelInfo - //TODO: clGetKernelWorkGroupInfo - - long clEnqueueNDRangeKernel(long queue, long kernel, int workDim, - ByteBuffer globalWorkOffset, ByteBuffer globalWorkSize, ByteBuffer localWorkSize); - - void clWaitForEvents(long[] events); - - void clWaitForEvent(long event); - - boolean isEventCompleted(long event); //uses clGetEventInfo - - void clReleaseEvent(long event); - - void clFlush(long queue); - - void clFinish(long queue); - -} diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index 68df8c807..b0168e618 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -34,6 +34,9 @@ package com.jme3.opencl; import com.jme3.asset.AssetInfo; import com.jme3.asset.AssetKey; import com.jme3.asset.AssetManager; +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.scene.mesh.IndexBuffer; import java.io.BufferedReader; @@ -70,69 +73,10 @@ public abstract class Context { return createBufferFromHost(data, MemoryAccess.READ_WRITE); } - public static enum ImageChannelOrder { - - R, Rx, A, - INTENSITY, - LUMINANCE, - RG, RGx, RA, - RGB, RGBx, - RGBA, - ARGB, BGRA - } - - public static enum ImageChannelType { - - SNORM_INT8, - SNORM_INT16, - UNORM_INT8, - UNROM_INT16, - UNORM_SHORT_565, - UNROM_SHORT_555, - UNORM_INT_101010, - SIGNED_INT8, - SIGNED_INT16, - SIGNED_INT32, - UNSIGNED_INT8, - UNSIGNED_INT16, - UNSIGNED_INT32, - HALF_FLOAT, - FLOAT - } - - public static class ImageFormat { //Struct - - public ImageChannelOrder channelOrder; - public ImageChannelType channelType; - } - - public static enum ImageType { - - IMAGE_1D, - IMAGE_1D_BUFFER, - IMAGE_2D, - IMAGE_3D, - IMAGE_1D_ARRAY, - IMAGE_2D_ARRAY - } - - public static class ImageDescriptor { //Struct - - public ImageType type; - public int width; - public int height; - public int depth; - public int arraySize; - public int rowPitch; - public int slicePitch; - public int numMipLevels; - public int numSamples; - public Buffer buffer; - } - public abstract Image createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr, ByteBuffer hostPtr); //TODO: add simplified methods for 1D, 2D, 3D textures - + public abstract ImageFormat[] querySupportedFormats(MemoryAccess access, ImageType type); + //Interop public abstract Buffer bindVertexBuffer(VertexBuffer vb); public abstract Buffer bindIndexBuffer(IndexBuffer ib); diff --git a/jme3-core/src/main/java/com/jme3/opencl/Image.java b/jme3-core/src/main/java/com/jme3/opencl/Image.java index 850dedd10..8c3134706 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Image.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Image.java @@ -31,10 +31,206 @@ */ package com.jme3.opencl; +import com.jme3.math.ColorRGBA; +import java.nio.ByteBuffer; +import java.util.Objects; + /** * * @author Sebastian Weiss */ public interface Image { + 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 + } + + public static enum ImageChannelOrder { + R, Rx, A, + INTENSITY, + LUMINANCE, + RG, RGx, RA, + RGB, RGBx, + RGBA, + ARGB, BGRA + } + + 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; + } + + } + + public static enum ImageType { + IMAGE_1D, + IMAGE_1D_BUFFER, + IMAGE_2D, + IMAGE_3D, + IMAGE_1D_ARRAY, + IMAGE_2D_ARRAY + } + + 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 int numMipLevels; //They must always be set to zero + public int numSamples; + */ + + public ImageDescriptor() { + } + + public ImageDescriptor(ImageType type, long width, long height, long depth, long arraySize, long rowPitch, long slicePitch) { + this.type = type; + this.width = width; + this.height = height; + this.depth = depth; + this.arraySize = arraySize; + this.rowPitch = rowPitch; + this.slicePitch = slicePitch; + } + 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; + } + + @Override + public String toString() { + return "ImageDescriptor{" + "type=" + type + ", width=" + width + ", height=" + height + ", depth=" + depth + ", arraySize=" + arraySize + ", rowPitch=" + rowPitch + ", slicePitch=" + slicePitch + '}'; + } + + } + + long getWidth(); + long getHeight(); + long getDepth(); + long getRowPitch(); + long getSlicePitch(); + long getArraySize(); + ImageFormat getImageFormat(); + ImageType getImageType(); + int getElementSize(); + + void readImage(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch); + Event readImageAsync(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch); + + void writeImage(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch); + Event writeImageAsync(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch); + + void copyTo(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region); + Event copyToAsync(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region); + + ImageMapping map(CommandQueue queue, long[] origin, long[] region, MappingAccess access); + ImageMapping mapAsync(CommandQueue queue, long[] origin, long[] region, MappingAccess access); + void unmap(CommandQueue queue, ImageMapping mapping); + + public static class ImageMapping { + public final ByteBuffer buffer; + public final long rowPitch; + public final long slicePitch; + 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 only work if the image channel is {@link ImageChannelType#FLOAT} + * or {@link ImageChannelType#HALF_FLOAT}. + * @param queue + * @param origin + * @param region + * @param color + * @return + */ + Event fillAsync(CommandQueue queue, long[] origin, long[] region, ColorRGBA color); + /** + * Fills the image with the specified color given as four integer variables. + * Does not work if the image channel is {@link ImageChannelType#FLOAT} + * or {@link ImageChannelType#HALF_FLOAT}. + * @param queue + * @param origin + * @param region + * @param color + * @return + */ + Event fillIntegerAsync(CommandQueue queue, long[] origin, long[] region, int[] color); + + Event copyToBufferAsync(CommandQueue queue, Buffer dest, long[] srcOrigin, long[] srcRegion, long destOffset); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java index 913a867d1..c726ae27a 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java @@ -102,6 +102,8 @@ public abstract class Kernel { 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); diff --git a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java index a5459c6b0..e89c598be 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java +++ b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java @@ -40,6 +40,8 @@ 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; @@ -78,6 +80,7 @@ public class HelloOpenCL extends SimpleApplication { 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)); BitmapText txt1 = new BitmapText(fnt); txt1.setText(str.toString()); @@ -85,6 +88,31 @@ public class HelloOpenCL extends SimpleApplication { guiNode.attachChild(txt1); } + 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 @@ -110,10 +138,7 @@ public class HelloOpenCL extends SimpleApplication { h1.rewind(); for (int i=0; i<256; ++i) { byte b = h1.get(); - if (b != (byte)i) { - System.err.println("Wrong byte read: expected="+i+", actual="+b); - return false; - } + assertEquals((byte) i, b, "Wrong byte read"); } //read buffer with offset @@ -125,12 +150,12 @@ public class HelloOpenCL extends SimpleApplication { h1.position(5); for (int i=0; i Date: Fri, 22 Apr 2016 16:11:55 +0200 Subject: [PATCH 11/40] implemented image operations --- .../main/java/com/jme3/opencl/Context.java | 4 +- .../src/main/java/com/jme3/opencl/Image.java | 2 +- .../java/jme3test/opencl/HelloOpenCL.java | 57 +++++ .../com/jme3/opencl/lwjgl/LwjglBuffer.java | 3 + .../com/jme3/opencl/lwjgl/LwjglContext.java | 4 +- .../com/jme3/opencl/lwjgl/LwjglEvent.java | 11 + .../com/jme3/opencl/lwjgl/LwjglImage.java | 230 +++++++++++++++--- 7 files changed, 278 insertions(+), 33 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index b0168e618..23e38cbd1 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -63,8 +63,8 @@ public abstract class Context { } public abstract CommandQueue createQueue(Device device); - public abstract Buffer createBuffer(int size, MemoryAccess access); - public Buffer createBuffer(int size) { + public abstract Buffer createBuffer(long size, MemoryAccess access); + public Buffer createBuffer(long size) { return createBuffer(size, MemoryAccess.READ_WRITE); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Image.java b/jme3-core/src/main/java/com/jme3/opencl/Image.java index 8c3134706..d69d6d7a4 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Image.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Image.java @@ -230,7 +230,7 @@ public interface Image { * @param color * @return */ - Event fillIntegerAsync(CommandQueue queue, long[] origin, long[] region, int[] color); + Event fillAsync(CommandQueue queue, long[] origin, long[] region, int[] color); Event copyToBufferAsync(CommandQueue queue, Buffer dest, long[] srcOrigin, long[] srcRegion, long destOffset); } diff --git a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java index e89c598be..79455af74 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java +++ b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java @@ -35,6 +35,7 @@ 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; @@ -86,6 +87,9 @@ public class HelloOpenCL extends SimpleApplication { 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) { @@ -223,6 +227,59 @@ public class HelloOpenCL extends SimpleApplication { 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); + image.copyToBufferAsync(clQueue, buffer, new long[]{10,10,0}, new long[]{500,1024,1}, 0); + //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, 0, 0); + Image image2 = clContext.createImage(MemoryAccess.READ_WRITE, format, descr, null); + //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); + } catch (AssertionError ex) { LOG.log(Level.SEVERE, "image test failed with an assertion error"); return false; diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java index 7e1563b80..0950db5fa 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java @@ -168,6 +168,9 @@ public class LwjglBuffer extends Buffer { @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(); diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java index 8c5b16f64..d9f4ab0d7 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java @@ -87,9 +87,9 @@ public class LwjglContext extends Context { } @Override - public Buffer createBuffer(int size, MemoryAccess access) { + public Buffer createBuffer(long size, MemoryAccess access) { long flags = Utils.getMemoryAccessFlags(access); - CLMem mem = CL10.clCreateBuffer(context, flags, (long) size, Utils.errorBuffer); + CLMem mem = CL10.clCreateBuffer(context, flags, size, Utils.errorBuffer); Utils.checkError(Utils.errorBuffer, "clCreateBuffer"); return new LwjglBuffer(mem); } diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java index ebe0ca458..3c7dfec28 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java @@ -32,6 +32,7 @@ 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; @@ -40,10 +41,14 @@ import org.lwjgl.opencl.CLEvent; * @author Sebastian Weiss */ public class LwjglEvent implements Event { + private static final Logger LOG = Logger.getLogger(LwjglEvent.class.getName()); private final CLEvent event; public LwjglEvent(CLEvent event) { this.event = event; + if (event == null) { + LOG.warning("event is null!"); + } } public CLEvent getEvent() { @@ -52,11 +57,17 @@ public class LwjglEvent implements Event { @Override public void waitForFinished() { + if (event==null) { + return; + } CL10.clWaitForEvents(event); } @Override public boolean isCompleted() { + if (event==null) { + return true; + } int status = event.getInfoInt(CL10.CL_EVENT_COMMAND_EXECUTION_STATUS); if (status == CL10.CL_SUCCESS) { return true; diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java index 4307fdf08..c847228c9 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java @@ -36,10 +36,7 @@ import com.jme3.opencl.*; import java.nio.ByteBuffer; import java.util.logging.Level; import java.util.logging.Logger; -import org.lwjgl.opencl.CL10; -import org.lwjgl.opencl.CL11; -import org.lwjgl.opencl.CL12; -import org.lwjgl.opencl.CLMem; +import org.lwjgl.opencl.*; import org.lwjgl.opencl.api.CLImageFormat; /** @@ -121,7 +118,7 @@ public class LwjglImage implements Image { case CL11.CL_Rx: return ImageChannelOrder.Rx; default: - //throw new OpenCLException("unknown image channel order id: " + order); + //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; } @@ -197,7 +194,7 @@ public class LwjglImage implements Image { case CL10.CL_UNSIGNED_INT8: return ImageChannelType.UNSIGNED_INT8; default: - //throw new OpenCLException("unknown image channel type id: " + type); + //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; } @@ -237,44 +234,46 @@ public class LwjglImage implements Image { case CL10.CL_MEM_OBJECT_IMAGE3D: return ImageType.IMAGE_3D; default: - throw new OpenCLException("Unknown image type id: " + type); + throw new com.jme3.opencl.OpenCLException("Unknown image type id: " + type); } } @Override public long getWidth() { - return image.getInfoSize(CL10.CL_IMAGE_WIDTH); + return image.getImageInfoSize(CL10.CL_IMAGE_WIDTH); } @Override public long getHeight() { - return image.getInfoSize(CL10.CL_IMAGE_HEIGHT); + return image.getImageInfoSize(CL10.CL_IMAGE_HEIGHT); } @Override public long getDepth() { - return image.getInfoSize(CL10.CL_IMAGE_DEPTH); + return image.getImageInfoSize(CL10.CL_IMAGE_DEPTH); } @Override public long getRowPitch() { - return image.getInfoSize(CL10.CL_IMAGE_ROW_PITCH); + return image.getImageInfoSize(CL10.CL_IMAGE_ROW_PITCH); } @Override public long getSlicePitch() { - return image.getInfoSize(CL10.CL_IMAGE_SLICE_PITCH); + return image.getImageInfoSize(CL10.CL_IMAGE_SLICE_PITCH); } @Override public long getArraySize() { - return image.getInfoSize(CL12.CL_IMAGE_ARRAY_SIZE); + 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())); + return new ImageFormat( + encodeImageChannelOrder(format.getChannelOrder()), + encodeImageChannelType(format.getChannelType())); } @Override @@ -285,67 +284,242 @@ public class LwjglImage implements Image { @Override public int getElementSize() { - return (int) image.getInfoSize(CL10.CL_IMAGE_ELEMENT_SIZE); + 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) { - throw new UnsupportedOperationException("Not supported yet."); + 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) { - throw new UnsupportedOperationException("Not supported yet."); + 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) { - throw new UnsupportedOperationException("Not supported yet."); + 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) { - throw new UnsupportedOperationException("Not supported yet."); + 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) { - throw new UnsupportedOperationException("Not supported yet."); + 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) { - throw new UnsupportedOperationException("Not supported yet."); + 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) { - throw new UnsupportedOperationException("Not supported yet."); + 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"); + 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 ImageMapping mapAsync(CommandQueue queue, long[] origin, long[] region, MappingAccess access) { - throw new UnsupportedOperationException("Not supported yet."); + 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, null, Utils.errorBuffer); + Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer"); + return new ImageMapping(buf, Utils.pointerBuffers[3].get(0), Utils.pointerBuffers[4].get(0)); } @Override public void unmap(CommandQueue queue, ImageMapping mapping) { - throw new UnsupportedOperationException("Not supported yet."); + 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) { - throw new UnsupportedOperationException("Not supported yet."); + 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? } @Override - public Event fillIntegerAsync(CommandQueue queue, long[] origin, long[] region, int[] color) { - throw new UnsupportedOperationException("Not supported yet."); + 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) { - throw new UnsupportedOperationException("Not supported yet."); + 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)); } } From 0d003275a7687fd65f55bbc7fd1cfb911758dc77 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Fri, 22 Apr 2016 21:12:10 +0200 Subject: [PATCH 12/40] implemented image sharing and added julia set testcase --- .../main/java/com/jme3/opencl/Context.java | 22 ++- .../src/main/java/com/jme3/opencl/Image.java | 4 + .../src/main/java/com/jme3/opencl/Kernel.java | 2 + .../java/jme3test/opencl/HelloOpenCL.java | 7 +- .../jme3test/opencl/TestWriteToTexture.java | 164 ++++++++++++++++++ .../resources/jme3test/opencl/JuliaSet.cl | 99 +++++++++++ .../com/jme3/opencl/lwjgl/LwjglContext.java | 61 +++++-- .../com/jme3/opencl/lwjgl/LwjglImage.java | 20 +++ 8 files changed, 358 insertions(+), 21 deletions(-) create mode 100644 jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java create mode 100644 jme3-examples/src/main/resources/jme3test/opencl/JuliaSet.cl diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index 23e38cbd1..2fe085dfe 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -39,6 +39,8 @@ import com.jme3.opencl.Image.ImageFormat; import com.jme3.opencl.Image.ImageType; import com.jme3.scene.VertexBuffer; import com.jme3.scene.mesh.IndexBuffer; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Texture; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -78,9 +80,23 @@ public abstract class Context { public abstract ImageFormat[] querySupportedFormats(MemoryAccess access, ImageType type); //Interop - public abstract Buffer bindVertexBuffer(VertexBuffer vb); - public abstract Buffer bindIndexBuffer(IndexBuffer ib); - public abstract Image bindImage(com.jme3.texture.Image image); + public abstract Buffer bindVertexBuffer(VertexBuffer vb, MemoryAccess access); + + public abstract Image bindImage(com.jme3.texture.Image image, Texture.Type textureType, int miplevel, MemoryAccess access); + public Image bindImage(Texture texture, int miplevel, MemoryAccess access) { + return bindImage(texture.getImage(), texture.getType(), miplevel, access); + } + public Image bindImage(Texture texture, MemoryAccess access) { + return bindImage(texture, 0, access); + } + 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); public abstract Program createProgramFromSourceCode(String sourceCode); diff --git a/jme3-core/src/main/java/com/jme3/opencl/Image.java b/jme3-core/src/main/java/com/jme3/opencl/Image.java index d69d6d7a4..564920f64 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Image.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Image.java @@ -233,4 +233,8 @@ public interface Image { Event fillAsync(CommandQueue queue, long[] origin, long[] region, int[] color); Event copyToBufferAsync(CommandQueue queue, Buffer dest, long[] srcOrigin, long[] srcRegion, long destOffset); + + + Event acquireImageForSharingAsync(CommandQueue queue); + Event releaseImageForSharingAsync(CommandQueue queue); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java index c726ae27a..8e9de6d70 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java @@ -150,6 +150,8 @@ public abstract class Kernel { 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); } diff --git a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java index 79455af74..95d052aed 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java +++ b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java @@ -46,9 +46,10 @@ import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; -/** Sample 1 - how to get started with the most simple JME 3 application. - * Display a blue 3D cube and view from all sides by - * moving the mouse and pressing the WASD keys. */ +/** + * Simple test checking if the basic functions of the OpenCL wrapper work + * @author Sebastian Weiss + */ public class HelloOpenCL extends SimpleApplication { private static final Logger LOG = Logger.getLogger(HelloOpenCL.class.getName()); diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java new file mode 100644 index 000000000..eb898278c --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java @@ -0,0 +1,164 @@ +/* + * 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 + * @author Sebastian Weiss + */ +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 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(true); + 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(); + //create kernel + Program program = clContext.createProgramFromSourceFiles(assetManager, "jme3test/opencl/JuliaSet.cl"); + program.build(); + kernel = program.createKernel("JuliaSet"); + C = new Vector2f(0.12f, -0.2f); + } + private void initOpenCL2() { + //bind image to OpenCL + texCL = clContext.bindImage(tex, MemoryAccess.WRITE_ONLY); + } + private void updateOpenCL(float tpf) { + //aquire resource + texCL.acquireImageForSharingAsync(clQueue); + //no need to wait for the returned event, since the kernel implicitely waits for it (same command queue) + + //execute kernel + kernel.Run1(clQueue, new WorkSize(settings.getWidth(), settings.getHeight()), texCL, C, 16); + + //release resource + texCL.releaseImageForSharingAsync(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); + } + } +} \ No newline at end of file diff --git a/jme3-examples/src/main/resources/jme3test/opencl/JuliaSet.cl b/jme3-examples/src/main/resources/jme3test/opencl/JuliaSet.cl new file mode 100644 index 000000000..d2a42d338 --- /dev/null +++ b/jme3-examples/src/main/resources/jme3test/opencl/JuliaSet.cl @@ -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); +} \ No newline at end of file diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java index d9f4ab0d7..b9f89d676 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java @@ -31,26 +31,22 @@ */ package com.jme3.opencl.lwjgl; -import com.jme3.asset.AssetInfo; -import com.jme3.asset.AssetKey; -import com.jme3.asset.AssetManager; 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.scene.mesh.IndexBuffer; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Texture; import java.nio.ByteBuffer; import java.nio.IntBuffer; -import java.util.Arrays; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.lwjgl.BufferUtils; import org.lwjgl.opencl.*; -import sun.misc.IOUtils; +import org.lwjgl.opengl.*; /** * @@ -154,23 +150,58 @@ public class LwjglContext extends Context { } @Override - public Buffer bindVertexBuffer(VertexBuffer vb) { - throw new UnsupportedOperationException("Not supported yet."); + 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 Buffer bindIndexBuffer(IndexBuffer ib) { - throw new UnsupportedOperationException("Not supported yet."); + 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 - public Image bindImage(com.jme3.texture.Image image) { - throw new UnsupportedOperationException("Not supported yet."); + 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.INFO, "Create program from source:\n{0}", 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"); diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java index c847228c9..e9b698129 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java @@ -477,6 +477,9 @@ public class LwjglImage implements Image { 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 @@ -522,4 +525,21 @@ public class LwjglImage implements Image { 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)); + } + 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)); + } } From 0c47bf18c94f9e78d95f393996caa189b74483be Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Sat, 23 Apr 2016 14:18:46 +0200 Subject: [PATCH 13/40] added memory managing: native resources are now automatically released --- .../src/main/java/com/jme3/opencl/Buffer.java | 6 +- .../java/com/jme3/opencl/CommandQueue.java | 4 +- .../main/java/com/jme3/opencl/Context.java | 3 +- .../src/main/java/com/jme3/opencl/Event.java | 2 +- .../src/main/java/com/jme3/opencl/Image.java | 3 +- .../src/main/java/com/jme3/opencl/Kernel.java | 4 +- .../java/com/jme3/opencl/OpenCLObject.java | 45 +++++++ .../com/jme3/opencl/OpenCLObjectManager.java | 118 ++++++++++++++++++ .../main/java/com/jme3/opencl/Program.java | 2 +- .../com/jme3/renderer/opengl/GLRenderer.java | 3 + .../jme3test/opencl/TestWriteToTexture.java | 9 ++ .../com/jme3/opencl/lwjgl/LwjglBuffer.java | 42 ++++++- .../jme3/opencl/lwjgl/LwjglCommandQueue.java | 20 +++ .../com/jme3/opencl/lwjgl/LwjglContext.java | 26 +++- .../com/jme3/opencl/lwjgl/LwjglEvent.java | 39 +++++- .../com/jme3/opencl/lwjgl/LwjglImage.java | 21 ++++ .../com/jme3/opencl/lwjgl/LwjglKernel.java | 21 +++- .../com/jme3/opencl/lwjgl/LwjglPlatform.java | 2 +- .../com/jme3/opencl/lwjgl/LwjglProgram.java | 26 +++- .../java/com/jme3/opencl/lwjgl/Utils.java | 43 ++++++- 20 files changed, 416 insertions(+), 23 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java create mode 100644 jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java diff --git a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java index 8db068dfa..8f39d7739 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java @@ -37,7 +37,7 @@ import java.nio.ByteBuffer; * * @author Sebastian Weiss */ -public abstract class Buffer { +public abstract class Buffer implements OpenCLObject { public abstract int getSize(); @@ -154,4 +154,8 @@ public abstract class Buffer { } public abstract Event copyToImageAsync(CommandQueue queue, Image dest, long srcOffset, long[] destOrigin, long[] destRegion); + + public abstract Event acquireBufferForSharingAsync(CommandQueue queue); + public abstract Event releaseBufferForSharingAsync(CommandQueue queue); + //TODO: add variants of the above two methods that don't create the event object, but release the event immediately } diff --git a/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java index a12e947e8..5f667e205 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java +++ b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java @@ -31,13 +31,11 @@ */ package com.jme3.opencl; -import java.nio.ByteBuffer; - /** * * @author Sebastian Weiss */ -public interface CommandQueue { +public interface CommandQueue extends OpenCLObject { void flush(); diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index 2fe085dfe..0b18fbb17 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -38,7 +38,6 @@ 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.scene.mesh.IndexBuffer; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture; import java.io.BufferedReader; @@ -55,7 +54,7 @@ import java.util.logging.Logger; * * @author Sebastian Weiss */ -public abstract class Context { +public abstract class Context implements OpenCLObject { private static final Logger LOG = Logger.getLogger(Context.class.getName()); public abstract List getDevices(); diff --git a/jme3-core/src/main/java/com/jme3/opencl/Event.java b/jme3-core/src/main/java/com/jme3/opencl/Event.java index 501df2593..ae72d0995 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Event.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Event.java @@ -35,7 +35,7 @@ package com.jme3.opencl; * * @author Sebastian Weiss */ -public interface Event { +public interface Event extends OpenCLObject { void waitForFinished(); diff --git a/jme3-core/src/main/java/com/jme3/opencl/Image.java b/jme3-core/src/main/java/com/jme3/opencl/Image.java index 564920f64..389ab265e 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Image.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Image.java @@ -39,7 +39,7 @@ import java.util.Objects; * * @author Sebastian Weiss */ -public interface Image { +public interface Image extends OpenCLObject { public static enum ImageChannelType { SNORM_INT8, @@ -237,4 +237,5 @@ public interface Image { Event acquireImageForSharingAsync(CommandQueue queue); Event releaseImageForSharingAsync(CommandQueue queue); + //TODO: add variants of the above two methods that don't create the event object, but release the event immediately } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java index 8e9de6d70..4aa87bd1a 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java @@ -40,7 +40,7 @@ import java.nio.ByteBuffer; * * @author Sebastian Weiss */ -public abstract class Kernel { +public abstract class Kernel implements OpenCLObject { protected final WorkSize globalWorkSize; protected final WorkSize workGroupSize; @@ -180,4 +180,6 @@ public abstract class Kernel { return Run(queue); } + //TODO: add variants of the above three methods that don't create the event object, but release the event immediately + } diff --git a/jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java new file mode 100644 index 000000000..e0b542e54 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java @@ -0,0 +1,45 @@ +/* + * 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; + +/** + * + * @author Sebastian Weiss + */ +public interface OpenCLObject { + + public static interface ObjectReleaser { + void release(); + } + ObjectReleaser getReleaser(); + +} diff --git a/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java new file mode 100644 index 000000000..2ba4293ef --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java @@ -0,0 +1,118 @@ +/* + * 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 Sebastian Weiss + */ +public class OpenCLObjectManager { + private static final Logger LOG = Logger.getLogger(OpenCLObjectManager.class.getName()); + private static final Level LOG_LEVEL1 = Level.INFO; + private static final Level LOG_LEVEL2 = Level.INFO; + /** + * 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 refQueue = new ReferenceQueue(); + private HashSet activeObjects = new HashSet(); + private int gcCounter = 0; + + private static class OpenCLObjectRef extends PhantomReference { + + private OpenCLObject.ObjectReleaser releaser; + + public OpenCLObjectRef(ReferenceQueue 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() { + 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, "NativeObjectManager: {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(); + } +} diff --git a/jme3-core/src/main/java/com/jme3/opencl/Program.java b/jme3-core/src/main/java/com/jme3/opencl/Program.java index 36203264a..91f588e79 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Program.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Program.java @@ -35,7 +35,7 @@ package com.jme3.opencl; * * @author Sebastian Weiss */ -public interface Program { +public interface Program extends OpenCLObject { void build(String args) throws KernelCompilationException; void build() throws KernelCompilationException; diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java index 70d25ccd4..1a8270435 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java @@ -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(); } diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java index eb898278c..87b6f6b68 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java @@ -61,6 +61,7 @@ public class TestWriteToTexture extends SimpleApplication implements AnalogListe private Vector2f C; private Image texCL; private boolean dragging; + private int gcCounter; public static void main(String[] args){ TestWriteToTexture app = new TestWriteToTexture(); @@ -84,6 +85,7 @@ public class TestWriteToTexture extends SimpleApplication implements AnalogListe guiNode.attachChild(pic); initCounter = 0; + gcCounter = 0; flyCam.setEnabled(false); inputManager.setCursorVisible(true); @@ -111,6 +113,13 @@ public class TestWriteToTexture extends SimpleApplication implements AnalogListe } else { updateOpenCL(tpf); } + + gcCounter++; + if (gcCounter > 10) { + Runtime.getRuntime().gc(); + gcCounter = 0; + } +// Runtime.getRuntime().runFinalization(); } private void initOpenCL1() { diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java index 0950db5fa..3efefb385 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java @@ -45,6 +45,7 @@ public class LwjglBuffer extends Buffer { public LwjglBuffer(CLMem buffer) { this.buffer = buffer; + OpenCLObjectManager.getInstance().registerObject(this); } public CLMem getBuffer() { return buffer; @@ -183,5 +184,44 @@ public class LwjglBuffer extends Buffer { 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 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 ObjectReleaser getReleaser() { + return new ReleaserImpl(buffer); + } + 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"); + } + } + + } } diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java index 801d761d5..55392157d 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java @@ -32,6 +32,7 @@ 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; @@ -45,6 +46,7 @@ public class LwjglCommandQueue implements CommandQueue { public LwjglCommandQueue(CLCommandQueue queue) { this.queue = queue; + OpenCLObjectManager.getInstance().registerObject(this); } public CLCommandQueue getQueue() { @@ -63,4 +65,22 @@ public class LwjglCommandQueue implements CommandQueue { Utils.checkError(ret, "clFinish"); } + @Override + public ObjectReleaser getReleaser() { + return new ReleaserImpl(queue); + } + private static class ReleaserImpl implements ObjectReleaser { + private CLCommandQueue queue; + private ReleaserImpl(CLCommandQueue queue) { + this.queue = queue; + } + @Override + public void release() { + if (queue != null) { + int ret = CL10.clReleaseCommandQueue(queue); + queue = null; + Utils.reportError(ret, "clReleaseCommandQueue"); + } + } + } } diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java index b9f89d676..f06632a3b 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java @@ -36,7 +36,6 @@ 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.scene.mesh.IndexBuffer; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture; import java.nio.ByteBuffer; @@ -60,6 +59,7 @@ public class LwjglContext extends Context { public LwjglContext(CLContext context, List devices) { this.context = context; this.devices = devices; + OpenCLObjectManager.getInstance().registerObject(this); } public CLContext getContext() { @@ -207,5 +207,27 @@ public class LwjglContext extends Context { Utils.checkError(Utils.errorBuffer, "clCreateProgramWithSource"); return new LwjglProgram(p, this); } - + + @Override + public ObjectReleaser getReleaser() { + return new ReleaserImpl(context, devices); + } + private static class ReleaserImpl implements ObjectReleaser { + private CLContext context; + private final List devices; + private ReleaserImpl(CLContext mem, List 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"); + } + } + + } } diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java index 3c7dfec28..2819c7bf9 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java @@ -32,6 +32,7 @@ package com.jme3.opencl.lwjgl; import com.jme3.opencl.Event; +import com.jme3.opencl.OpenCLObjectManager; import java.util.logging.Logger; import org.lwjgl.opencl.CL10; import org.lwjgl.opencl.CLEvent; @@ -42,18 +43,29 @@ import org.lwjgl.opencl.CLEvent; */ public class LwjglEvent implements Event { private static final Logger LOG = Logger.getLogger(LwjglEvent.class.getName()); - private final CLEvent event; + private CLEvent event; public LwjglEvent(CLEvent event) { this.event = event; if (event == null) { LOG.warning("event is null!"); + } else { + OpenCLObjectManager.getInstance().registerObject(this); } } public CLEvent getEvent() { return event; } + + protected void release() { + if (event != null && event.isValid()) { + int ret = CL10.clReleaseEvent(event); + event = null; + Utils.reportError(ret, "clReleaseEvent"); + LOG.finer("Event deleted"); + } + } @Override public void waitForFinished() { @@ -61,6 +73,7 @@ public class LwjglEvent implements Event { return; } CL10.clWaitForEvents(event); + release(); //short cut to save resources } @Override @@ -70,6 +83,7 @@ public class LwjglEvent implements Event { } 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"); @@ -78,5 +92,28 @@ public class LwjglEvent implements Event { return false; } } + + @Override + public ObjectReleaser getReleaser() { + return new ReleaserImpl(event); + } + 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"); + } + } + + } } diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java index e9b698129..52be48d94 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java @@ -50,6 +50,7 @@ public class LwjglImage implements Image { public LwjglImage(CLMem image) { this.image = image; + OpenCLObjectManager.getInstance().registerObject(this); } public CLMem getImage() { @@ -542,4 +543,24 @@ public class LwjglImage implements Image { long event = Utils.pointerBuffers[0].get(0); return new LwjglEvent(q.getCLEvent(event)); } + + @Override + public ObjectReleaser getReleaser() { + return new ReleaserImpl(image); + } + private static class ReleaserImpl implements ObjectReleaser { + private CLMem mem; + private ReleaserImpl(CLMem mem) { + this.mem = mem; + } + @Override + public void release() { + if (mem != null) { + int ret = CL10.clReleaseMemObject(mem); + mem = null; + Utils.reportError(ret, "clReleaseMemObject"); + } + } + + } } diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java index 9bb80ebca..19d536e2a 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java @@ -52,6 +52,7 @@ public class LwjglKernel extends Kernel { public LwjglKernel(CLKernel kernel) { this.kernel = kernel; + OpenCLObjectManager.getInstance().registerObject(this); } public CLKernel getKernel() { @@ -215,5 +216,23 @@ public class LwjglKernel extends Kernel { Utils.checkError(ret, "clEnqueueNDRangeKernel"); return new LwjglEvent(q.getCLEvent(Utils.pointerBuffers[0].get(0))); } - + + @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"); + } + } + } } diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java index 67f7910be..7982ff2de 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java @@ -123,5 +123,5 @@ public final class LwjglPlatform implements Platform { public Collection getExtensions() { return Arrays.asList(platform.getInfoString(CL10.CL_PLATFORM_EXTENSIONS).split(" ")); } - + } diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java index a3239e5fd..2ce274754 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java @@ -33,8 +33,8 @@ package com.jme3.opencl.lwjgl; import com.jme3.opencl.Kernel; import com.jme3.opencl.KernelCompilationException; +import com.jme3.opencl.OpenCLObjectManager; import com.jme3.opencl.Program; -import java.util.ArrayList; import java.util.logging.Level; import java.util.logging.Logger; import org.lwjgl.PointerBuffer; @@ -53,6 +53,7 @@ public class LwjglProgram implements Program { public LwjglProgram(CLProgram program, LwjglContext context) { this.program = program; this.context = context; + OpenCLObjectManager.getInstance().registerObject(this); } public CLProgram getProgram() { @@ -107,5 +108,26 @@ public class LwjglProgram implements Program { } return kx; } - + + @Override + public ObjectReleaser getReleaser() { + return new ReleaserImpl(program); + } + private static class ReleaserImpl implements ObjectReleaser { + private CLProgram program; + private ReleaserImpl(CLProgram program) { + 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"); + } + */ + } + } } diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java index 68805bd60..07e36506e 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java @@ -34,19 +34,32 @@ 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.CL10; -import org.lwjgl.opencl.CL12; -import org.lwjgl.opencl.Util; +import org.lwjgl.opencl.*; /** * * @author Sebastian Weiss */ 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 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()); @@ -95,8 +108,27 @@ public class Utils { checkError(errorBuffer.get(0), callName); } public static void checkError(int error, String callName) { - //TODO: proper handling - Util.checkCLError(error); + 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) { @@ -129,4 +161,5 @@ public class Utils { default: throw new IllegalArgumentException("Unknown mapping access: "+ma); } } + } From 60f10bb604881ba7473391c3d4fd2d86ac576735 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Sat, 23 Apr 2016 14:40:48 +0200 Subject: [PATCH 14/40] renamed DefaultPlatformChooser and moved it to the core, some small fixes --- .../main/java/com/jme3/opencl/DefaultPlatformChooser.java | 6 +++--- .../main/java/com/jme3/opencl/OpenCLObjectManager.java | 8 ++++++-- jme3-core/src/main/java/com/jme3/system/AppSettings.java | 4 +++- .../src/main/java/jme3test/opencl/TestWriteToTexture.java | 6 ++++-- .../src/main/java/com/jme3/system/lwjgl/LwjglContext.java | 4 ++-- 5 files changed, 18 insertions(+), 10 deletions(-) rename jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/PlatformChooserImpl.java => jme3-core/src/main/java/com/jme3/opencl/DefaultPlatformChooser.java (94%) diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/PlatformChooserImpl.java b/jme3-core/src/main/java/com/jme3/opencl/DefaultPlatformChooser.java similarity index 94% rename from jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/PlatformChooserImpl.java rename to jme3-core/src/main/java/com/jme3/opencl/DefaultPlatformChooser.java index fd3a7147b..e07bdf4e1 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/PlatformChooserImpl.java +++ b/jme3-core/src/main/java/com/jme3/opencl/DefaultPlatformChooser.java @@ -29,7 +29,7 @@ * 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; +package com.jme3.opencl; import com.jme3.opencl.Device; import com.jme3.opencl.Platform; @@ -42,8 +42,8 @@ import java.util.logging.Logger; * * @author Sebastian Weiss */ -public class PlatformChooserImpl implements PlatformChooser { - private static final Logger LOG = Logger.getLogger(PlatformChooserImpl.class.getName()); +public class DefaultPlatformChooser implements PlatformChooser { + private static final Logger LOG = Logger.getLogger(DefaultPlatformChooser.class.getName()); @Override public List chooseDevices(List platforms) { diff --git a/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java index 2ba4293ef..7eebf4bb8 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java +++ b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java @@ -43,8 +43,8 @@ import java.util.logging.Logger; */ public class OpenCLObjectManager { private static final Logger LOG = Logger.getLogger(OpenCLObjectManager.class.getName()); - private static final Level LOG_LEVEL1 = Level.INFO; - private static final Level LOG_LEVEL2 = Level.INFO; + private static final Level LOG_LEVEL1 = Level.FINER; + private static final Level LOG_LEVEL2 = Level.FINE; /** * Call Runtime.getRuntime().gc() every these frames */ @@ -84,6 +84,10 @@ public class OpenCLObjectManager { } public void deleteUnusedObjects() { + if (activeObjects.isEmpty()) { + return; //nothing to do + } + gcCounter++; if (gcCounter >= GC_FREQUENCY) { //The program is that the OpenCLObjects are so small that they are diff --git a/jme3-core/src/main/java/com/jme3/system/AppSettings.java b/jme3-core/src/main/java/com/jme3/system/AppSettings.java index 991854ebf..4fc23a32e 100644 --- a/jme3-core/src/main/java/com/jme3/system/AppSettings.java +++ b/jme3-core/src/main/java/com/jme3/system/AppSettings.java @@ -31,6 +31,7 @@ */ package com.jme3.system; +import com.jme3.opencl.DefaultPlatformChooser; import com.jme3.opencl.PlatformChooser; import java.io.IOException; import java.io.InputStream; @@ -162,6 +163,7 @@ public final class AppSettings extends HashMap { defaults.put("Resizable", false); defaults.put("SwapBuffers", true); defaults.put("OpenCL", false); + defaults.put("OpenCLPlatformChooser", DefaultPlatformChooser.class.getName()); // defaults.put("Icons", null); } @@ -1039,7 +1041,7 @@ public final class AppSettings extends HashMap { * Sets a custom platform chooser. This chooser specifies which platform and * which devices are used for the OpenCL context. * - * Default: not set, an implementation defined one is used. + * Default: an implementation defined one. * * @param chooser the class of the chooser, must have a default constructor */ diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java index 87b6f6b68..f453c4fd2 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java @@ -46,7 +46,9 @@ import com.jme3.ui.Picture; import java.util.logging.Logger; /** - * This test class tests the capability to write to a GL texture from OpenCL + * 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. + * * @author Sebastian Weiss */ public class TestWriteToTexture extends SimpleApplication implements AnalogListener, ActionListener { @@ -67,7 +69,7 @@ public class TestWriteToTexture extends SimpleApplication implements AnalogListe TestWriteToTexture app = new TestWriteToTexture(); AppSettings settings = new AppSettings(true); settings.setOpenCLSupport(true); - settings.setVSync(true); + settings.setVSync(false); app.setSettings(settings); app.start(); // start the game } diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index 32767fa9b..68d46b1c7 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -39,7 +39,7 @@ 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.PlatformChooserImpl; +import com.jme3.opencl.DefaultPlatformChooser; import com.jme3.renderer.Renderer; import com.jme3.renderer.RendererException; import com.jme3.renderer.lwjgl.LwjglGL; @@ -319,7 +319,7 @@ public abstract class LwjglContext implements JmeContext { } } if (chooser == null) { - chooser = new PlatformChooserImpl(); + chooser = new DefaultPlatformChooser(); } List choosenDevices = chooser.chooseDevices(platforms); List devices = new ArrayList<>(choosenDevices.size()); From 03282a7c8616bfed0747e351ad155b815ea57d18 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Sun, 24 Apr 2016 14:09:09 +0200 Subject: [PATCH 15/40] added example for vertex buffer sharing --- .../opencl/TestVertexBufferSharing.java | 144 ++++++++++++++++++ .../jme3test/opencl/TestWriteToTexture.java | 6 - 2 files changed, 144 insertions(+), 6 deletions(-) create mode 100644 jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java new file mode 100644 index 000000000..6b251641c --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java @@ -0,0 +1,144 @@ +/* + * 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 java.util.logging.Logger; + +/** + * This test class tests the capability to read and modify an OpenGL vertex buffer. + * + * @author Sebastian Weiss + */ +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 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); + 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(); + clQueue = clContext.createQueue(); + //create kernel + 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 program = clContext.createProgramFromSourceCode(source); + program.build(); + kernel = program.createKernel("ScaleKernel"); + } + private void initOpenCL2() { + //bind vertex buffer to OpenCL + VertexBuffer vb = geom.getMesh().getBuffer(VertexBuffer.Type.Position); + buffer = clContext.bindVertexBuffer(vb, MemoryAccess.READ_WRITE); + ws = new WorkSize(geom.getMesh().getVertexCount()); + } + private void updateOpenCL(float tpf) { + //advect time + time += tpf; + + //aquire resource + buffer.acquireBufferForSharingAsync(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.Run1(clQueue, ws, buffer, scale); + + //release resource + buffer.releaseBufferForSharingAsync(clQueue); + } + +} \ No newline at end of file diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java index f453c4fd2..2f583ea61 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java @@ -116,12 +116,6 @@ public class TestWriteToTexture extends SimpleApplication implements AnalogListe updateOpenCL(tpf); } - gcCounter++; - if (gcCounter > 10) { - Runtime.getRuntime().gc(); - gcCounter = 0; - } -// Runtime.getRuntime().runFinalization(); } private void initOpenCL1() { From 196cbc80421981b4e28ed675808ca059c4795bd1 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Sun, 24 Apr 2016 20:13:51 +0200 Subject: [PATCH 16/40] started with the documentation --- .../src/main/java/com/jme3/opencl/Buffer.java | 267 ++++++++++++++++-- .../jme3/opencl/DefaultPlatformChooser.java | 7 +- .../opencl/KernelCompilationException.java | 12 +- .../java/com/jme3/opencl/package-info.java | 111 ++++++++ .../com/jme3/opencl/lwjgl/LwjglBuffer.java | 30 +- .../com/jme3/opencl/lwjgl/LwjglContext.java | 2 +- 6 files changed, 387 insertions(+), 42 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java index 8f39d7739..5e2d56cad 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java @@ -34,98 +34,283 @@ 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. + *
+ * Buffers are created by the {@link Context}. + *
+ * 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 Sebastian Weiss */ public abstract class Buffer implements OpenCLObject { - public abstract int getSize(); + /** + * @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(); - public abstract void read(CommandQueue queue, ByteBuffer dest, int size, int offset); + /** + * 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); - public void read(CommandQueue queue, ByteBuffer dest, int size) { + /** + * 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()); } - public abstract Event readAsync(CommandQueue queue, ByteBuffer dest, int size, int offset); + /** + * 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); - public Event readAsync(CommandQueue queue, ByteBuffer dest, int size) { + /** + * 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()); } - public abstract void write(CommandQueue queue, ByteBuffer src, int size, int offset); + /** + * 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); - public void write(CommandQueue queue, ByteBuffer src, int size) { + /** + * 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()); } - public abstract Event writeAsync(CommandQueue queue, ByteBuffer src, int size, int offset); + /** + * 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); - public Event writeAsync(CommandQueue queue, ByteBuffer src, int size) { + /** + * 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()); } - public abstract void copyTo(CommandQueue queue, Buffer dest, int size, int srcOffset, int destOffset); + /** + * 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); - public void copyTo(CommandQueue queue, Buffer dest, int size) { + /** + * 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()); } - public abstract Event copyToAsync(CommandQueue queue, Buffer dest, int size, int srcOffset, int destOffset); + /** + * 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); - public Event copyToAsync(CommandQueue queue, Buffer dest, int size) { + /** + * 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()); } - public abstract ByteBuffer map(CommandQueue queue, int size, int offset, MappingAccess access); + /** + * 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.
+ * Important: 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); - public ByteBuffer map(CommandQueue queue, int size, MappingAccess access) { + /** + * Alternative version of {@link #map(com.jme3.opencl.CommandQueue, long, long, com.jme3.opencl.MappingAccess) }, + * sets {@code offset} to zero. + * Important: 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() }. + * Important: 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); - public abstract AsyncMapping mapAsync(CommandQueue queue, int size, int offset, MappingAccess access); - public AsyncMapping mapAsync(CommandQueue queue, int size, MappingAccess access) { + /** + * 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.
+ * Important: 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. + * Important: 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() }. + * Important: 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); } - public abstract Event fillAsync(CommandQueue queue, ByteBuffer pattern, int size, int offset); - - //TODO: copy to image + /** + * 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. @@ -144,18 +329,58 @@ public abstract class Buffer implements OpenCLObject { 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. + *
+ * 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); + /** + * 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); //TODO: add variants of the above two methods that don't create the event object, but release the event immediately } diff --git a/jme3-core/src/main/java/com/jme3/opencl/DefaultPlatformChooser.java b/jme3-core/src/main/java/com/jme3/opencl/DefaultPlatformChooser.java index e07bdf4e1..70583a367 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/DefaultPlatformChooser.java +++ b/jme3-core/src/main/java/com/jme3/opencl/DefaultPlatformChooser.java @@ -31,15 +31,14 @@ */ package com.jme3.opencl; -import com.jme3.opencl.Device; -import com.jme3.opencl.Platform; -import com.jme3.opencl.PlatformChooser; 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 Sebastian Weiss */ public class DefaultPlatformChooser implements PlatformChooser { diff --git a/jme3-core/src/main/java/com/jme3/opencl/KernelCompilationException.java b/jme3-core/src/main/java/com/jme3/opencl/KernelCompilationException.java index 37d7a07b7..478f62c2c 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/KernelCompilationException.java +++ b/jme3-core/src/main/java/com/jme3/opencl/KernelCompilationException.java @@ -31,7 +31,13 @@ */ 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 Sebastian Weiss + */ public class KernelCompilationException extends OpenCLException { private final String log; @@ -41,6 +47,10 @@ public class KernelCompilationException extends OpenCLException { this.log = log; } + /** + * The output of the compiler + * @return + */ public String getLog() { return log; } diff --git a/jme3-core/src/main/java/com/jme3/opencl/package-info.java b/jme3-core/src/main/java/com/jme3/opencl/package-info.java index 66aa0db47..5b4fcbc0b 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/package-info.java +++ b/jme3-core/src/main/java/com/jme3/opencl/package-info.java @@ -32,6 +32,117 @@ /** * This package contains an API for using OpenCL together with jME3. + *

+ * Activation:
+ * 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}. + * + *

+ * First steps:
+ * 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. + *
+ * Programs and Kernels: + * 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. + *
+ * Buffers and Images: + * 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. + *
+ * Events: + * 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. + * + *

+ * Interoperability between OpenCL and jME3:
+ * This Wrapper allows to share jME3 Images and VertexBuffers with OpenCL.
+ * {@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.
+ * {@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. + *
+ * Important: 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. + * + *

+ * Experts: choosing the right platform and devices
+ * 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}. + * + *

+ * Exception handling:
+ * 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: + *

    + *
  • {@code NullPointerException}: one of the arguments is {@code null} and + * {@code null} is not allowed
  • + *
  • {@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
  • + *
  • {@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.
  • + *
*/ package com.jme3.opencl; diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java index 3efefb385..7b9adb4ba 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java @@ -52,8 +52,8 @@ public class LwjglBuffer extends Buffer { } @Override - public int getSize() { - return buffer.getInfoInt(CL10.CL_MEM_SIZE); + public long getSize() { + return buffer.getInfoSize(CL10.CL_MEM_SIZE); } @Override @@ -62,18 +62,18 @@ public class LwjglBuffer extends Buffer { } @Override - public void read(CommandQueue queue, ByteBuffer dest, int size, int offset) { + 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(dest.position() + size); + 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, int size, int offset) { + 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(dest.position() + size); + 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]); @@ -83,18 +83,18 @@ public class LwjglBuffer extends Buffer { } @Override - public void write(CommandQueue queue, ByteBuffer src, int size, int offset) { + 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(src.position() + size); + 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, int size, int offset) { + 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(src.position() + size); + 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]); @@ -104,7 +104,7 @@ public class LwjglBuffer extends Buffer { } @Override - public void copyTo(CommandQueue queue, Buffer dest, int size, int srcOffset, int destOffset) { + 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]); @@ -115,7 +115,7 @@ public class LwjglBuffer extends Buffer { } @Override - public Event copyToAsync(CommandQueue queue, Buffer dest, int size, int srcOffset, int destOffset) { + 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]); @@ -125,7 +125,7 @@ public class LwjglBuffer extends Buffer { } @Override - public ByteBuffer map(CommandQueue queue, int size, int offset, MappingAccess access) { + public ByteBuffer map(CommandQueue queue, long size, long offset, MappingAccess access) { CLCommandQueue q = ((LwjglCommandQueue) queue).getQueue(); long flags = Utils.getMappingAccessFlags(access); Utils.errorBuffer.rewind(); @@ -146,7 +146,7 @@ public class LwjglBuffer extends Buffer { } @Override - public com.jme3.opencl.Buffer.AsyncMapping mapAsync(CommandQueue queue, int size, int offset, MappingAccess access) { + 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(); @@ -158,7 +158,7 @@ public class LwjglBuffer extends Buffer { } @Override - public Event fillAsync(CommandQueue queue, ByteBuffer pattern, int size, int offset) { + 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]); diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java index f06632a3b..eddfaf4cc 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java @@ -183,7 +183,7 @@ public class LwjglContext extends Context { throw new IllegalArgumentException("renderbuffer was not yet uploaded to the GPU"); } long memFlags = Utils.getMemoryAccessFlags(access); - Utils.errorBuffer.rewind(); + Utils.errorBuffer.rewind(); CLMem mem = CL10GL.clCreateFromGLRenderbuffer(context, memFlags, renderbuffer, Utils.errorBuffer); Utils.checkError(Utils.errorBuffer, "clCreateFromGLRenderbuffer"); return new LwjglImage(mem); From ee43853ff18447712a628a58f02f0ab2ceac3e37 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Mon, 25 Apr 2016 16:33:10 +0200 Subject: [PATCH 17/40] docs, docs, docs --- .../java/com/jme3/opencl/CommandQueue.java | 22 +- .../main/java/com/jme3/opencl/Context.java | 235 +++++++++++++++++- .../src/main/java/com/jme3/opencl/Device.java | 213 +++++++++++++++- .../src/main/java/com/jme3/opencl/Image.java | 5 +- .../java/jme3test/opencl/HelloOpenCL.java | 12 +- .../com/jme3/opencl/lwjgl/LwjglContext.java | 4 +- 6 files changed, 474 insertions(+), 17 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java index 5f667e205..761df702a 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java +++ b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java @@ -32,13 +32,33 @@ 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. + *
+ * 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 Sebastian Weiss */ public interface CommandQueue extends OpenCLObject { + /** + * 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. + */ 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. + */ void finish(); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index 0b18fbb17..e108ad729 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -50,44 +50,216 @@ import java.util.logging.Level; import java.util.logging.Logger; /** - * The central OpenCL context. Every actions start from here. - * + * The central OpenCL context. Every action starts from here. + * The context can be obtained by {@link com.jme3.system.JmeContext#getOpenCLContext() }. + *

+ * The context is used to: + *

    + *
  • Query the available devices
  • + *
  • Create a command queue
  • + *
  • Create buffers and images
  • + *
  • Created buffers and images shared with OpenGL vertex buffers, textures and renderbuffers
  • + *
  • Create program objects from source code and source files
  • + *
* @author Sebastian Weiss */ public abstract class Context implements OpenCLObject { private static final Logger LOG = Logger.getLogger(Context.class.getName()); + /** + * 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. + *
+ * The available devices were specified by a {@link PlatformChooser}. + * @return + */ public abstract List 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); } - public abstract Image createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr, ByteBuffer hostPtr); + /** + * Creates a new 1D, 2D, 3D image.
+ * {@code ImageFormat} specifies the element type and order, like RGBA of floats.
+ * {@code ImageDescriptor} specifies the dimension of the image.
+ * 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. + *
+ * 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). + *
+ * Note: The vertex buffer must already been uploaded to the GPU, + * i.e. it must be used at least once for drawing. + *

+ * 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). + *
+ * Note: The image must already been uploaded to the GPU, + * i.e. it must be used at least once for drawing. + *

+ * 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). + *
+ * Note: The image must already been uploaded to the GPU, + * i.e. it must be used at least once for drawing. + *

+ * 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. + *

+ * 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. + *
+ * This can be used as an alternative to post processing effects + * (e.g. reduce sum operations, needed e.g. for tone mapping). + *
+ * Note: The renderbuffer must already been uploaded to the GPU, + * i.e. it must be used at least once for drawing. + *

+ * 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); @@ -97,12 +269,61 @@ public abstract class Context implements OpenCLObject { } 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); + /** + * 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. + *

+ * The typical use case is: + *

    + *
  • The include string contains some compiler constants like the grid size
  • + *
  • Some common OpenCL files used as libraries (Convention: file names end with {@code .clh}
  • + *
  • One main OpenCL file containing the actual kernels (Convention: file name ends with {@code .cl})
  • + *
+ * Note: Files that can't be loaded are skipped.
+ * + * The actual creation is handled by {@link #createProgramFromSourceCode(java.lang.String) }. + * + * @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 + */ 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. + *

+ * The typical use case is: + *

    + *
  • The include string contains some compiler constants like the grid size
  • + *
  • Some common OpenCL files used as libraries (Convention: file names end with {@code .clh}
  • + *
  • One main OpenCL file containing the actual kernels (Convention: file name ends with {@code .cl})
  • + *
+ * Note: Files that can't be loaded are skipped.
+ * + * The actual creation is handled by {@link #createProgramFromSourceCode(java.lang.String) }. + * + * @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 + */ public Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, List resources) { StringBuilder str = new StringBuilder(); str.append(include); @@ -127,10 +348,18 @@ public abstract class Context implements OpenCLObject { return createProgramFromSourceCode(str.toString()); } + /** + * Alternative version of {@link #createProgramFromSourceFilesWithInclude(com.jme3.asset.AssetManager, java.lang.String, java.lang.String...) } + * with an empty include string + */ 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 + */ public Program createProgramFromSourceFiles(AssetManager assetManager, List resources) { return createProgramFromSourceFilesWithInclude(assetManager, "", resources); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Device.java b/jme3-core/src/main/java/com/jme3/opencl/Device.java index 5d9095b6f..aaa349d58 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Device.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Device.java @@ -34,13 +34,26 @@ 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) }). + *

+ * This class is used to query the capabilities of the underlying device. + * * @author Sebastian Weiss */ public interface Device { + /** + * @return the platform accociated with this device + */ Platform getPlatform(); + /** + * The device type + */ public static enum DeviceType { DEFAULT, CPU, @@ -48,55 +61,251 @@ public interface Device { 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 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. + *
+ * 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:
+ * 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).
+ * 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. + *
+ * 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.
+ * 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(); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Image.java b/jme3-core/src/main/java/com/jme3/opencl/Image.java index 389ab265e..4e595d974 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Image.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Image.java @@ -131,6 +131,7 @@ public interface Image extends OpenCLObject { 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; @@ -139,7 +140,7 @@ public interface Image extends OpenCLObject { public ImageDescriptor() { } - public ImageDescriptor(ImageType type, long width, long height, long depth, long arraySize, long rowPitch, long slicePitch) { + 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; @@ -147,6 +148,7 @@ public interface Image extends OpenCLObject { this.arraySize = arraySize; this.rowPitch = rowPitch; this.slicePitch = slicePitch; + this.hostPtr = hostPtr; } public ImageDescriptor(ImageType type, long width, long height, long depth, long arraySize) { this.type = type; @@ -156,6 +158,7 @@ public interface Image extends OpenCLObject { this.arraySize = arraySize; this.rowPitch = 0; this.slicePitch = 0; + hostPtr = null; } @Override diff --git a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java index 95d052aed..e697dc584 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java +++ b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java @@ -174,10 +174,6 @@ public class HelloOpenCL extends SimpleApplication { String include = "#define TYPE float\n"; Program program = clContext.createProgramFromSourceFilesWithInclude(assetManager, include, "jme3test/opencl/Blas.cl"); program.build(); - Kernel[] kernels = program.createAllKernels(); - for (Kernel k : kernels) { - System.out.println("available kernel: "+k.getName()); - } Kernel kernel = program.createKernel("Fill"); System.out.println("number of args: "+kernel.getArgCount()); @@ -218,8 +214,8 @@ public class HelloOpenCL extends SimpleApplication { //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, 0, 0); - Image image = clContext.createImage(MemoryAccess.READ_WRITE, format, descr, null); + 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 @@ -258,8 +254,8 @@ public class HelloOpenCL extends SimpleApplication { //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, 0, 0); - Image image2 = clContext.createImage(MemoryAccess.READ_WRITE, format, descr, null); + 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 diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java index eddfaf4cc..13af4946f 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java @@ -100,7 +100,7 @@ public class LwjglContext extends Context { } @Override - public Image createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr, ByteBuffer hostPtr) { + public Image createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr) { long memFlags = Utils.getMemoryAccessFlags(access); Utils.errorBuffer.rewind(); //fill image format @@ -116,7 +116,7 @@ public class LwjglContext extends Context { .put(0).put(0).put(0); Utils.b80.rewind(); //create image - CLMem mem = CL12.clCreateImage(context, memFlags, Utils.tempBuffers[0].b16, Utils.b80, hostPtr, Utils.errorBuffer); + 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); } From 510c40955fd47d9be0b0fe5cf3b8c9e4f810cc05 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Tue, 26 Apr 2016 10:16:48 +0200 Subject: [PATCH 18/40] some more documentation --- .../src/main/java/com/jme3/opencl/Event.java | 12 +- .../src/main/java/com/jme3/opencl/Image.java | 277 +++++++++++++++++- 2 files changed, 275 insertions(+), 14 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/opencl/Event.java b/jme3-core/src/main/java/com/jme3/opencl/Event.java index ae72d0995..4e5400459 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Event.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Event.java @@ -32,12 +32,22 @@ 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 Sebastian Weiss */ public interface Event extends OpenCLObject { + /** + * Waits until the action has finished (blocking) + */ void waitForFinished(); + /** + * Tests if the action is completed + * @return {@code true} if the action is completed + */ boolean isCompleted(); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Image.java b/jme3-core/src/main/java/com/jme3/opencl/Image.java index 4e595d974..368b9a62d 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Image.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Image.java @@ -36,11 +36,49 @@ import java.nio.ByteBuffer; import java.util.Objects; /** + * Wrapper for an OpenCL image. + *
+ * An image object is similar to a {@link Buffer}, but with a specific element + * format and buffer structure. + *
+ * 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. + *
+ * 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). + * + *

+ * Most methods take long arrays as input: {@code long[] origin} and {@code long[] region}. + * Both are arrays of length 3. + *
+ * origin 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. + *
+ * region 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 Sebastian Weiss */ public interface Image extends OpenCLObject { + /** + * {@code ImageChannelType} describes the size of the channel data type. + */ public static enum ImageChannelType { SNORM_INT8, SNORM_INT16, @@ -59,6 +97,10 @@ public interface Image extends OpenCLObject { 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, @@ -69,6 +111,10 @@ public interface Image extends OpenCLObject { ARGB, BGRA } + /** + * Describes the image format, consisting of + * {@link ImageChannelOrder} and {@link ImageChannelType}. + */ public static class ImageFormat { //Struct public ImageChannelOrder channelOrder; public ImageChannelType channelType; @@ -114,6 +160,9 @@ public interface Image extends OpenCLObject { } + /** + * The possible image types / dimensions. + */ public static enum ImageType { IMAGE_1D, IMAGE_1D_BUFFER, @@ -123,6 +172,15 @@ public interface Image extends OpenCLObject { IMAGE_2D_ARRAY } + /** + * The image descriptor structure describes the type and dimensions of the image or image array. + *

+ * There exists two constructors:
+ * {@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).
+ * {@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; @@ -140,6 +198,17 @@ public interface Image extends OpenCLObject { 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; @@ -150,6 +219,15 @@ public interface Image extends OpenCLObject { 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; @@ -168,33 +246,175 @@ public interface Image extends OpenCLObject { } + /** + * @return the width of the image + */ long getWidth(); + /** + * @return the height of the image + */ long getHeight(); + /** + * @return the depth of the image + */ long getDepth(); + /** + * @return the row pitch when the image was created from a host buffer + * @see ImageDescriptor#ImageDescriptor(com.jme3.opencl.Image.ImageType, long, long, long, long, long, long, java.nio.ByteBuffer) + */ long getRowPitch(); + /** + * @return the slice pitch when the image was created from a host buffer + * @see ImageDescriptor#ImageDescriptor(com.jme3.opencl.Image.ImageType, long, long, long, long, long, long, java.nio.ByteBuffer) + */ long getSlicePitch(); + /** + * @return the number of elements in the image array + * @see ImageType#IMAGE_1D_ARRAY + * @see ImageType#IMAGE_2D_ARRAY + */ long getArraySize(); + /** + * @return the image format + */ ImageFormat getImageFormat(); + /** + * @return the image type + */ ImageType getImageType(); + /** + * @return the number of bytes per pixel + */ 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} + */ 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 + */ Event readImageAsync(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch); - void writeImage(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch); - Event writeImageAsync(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} + */ + 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 + */ + Event writeImageAsync(CommandQueue queue, ByteBuffer src, long[] origin, long[] region, long rowPitch, long slicePitch); + /** + * Performs a blocking copy operation from one image to another. + * Important: 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 + */ void copyTo(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region); + /** + * Performs an async/non-blocking copy operation from one image to another. + * Important: 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 + */ 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) + */ 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) + */ ImageMapping mapAsync(CommandQueue queue, long[] origin, long[] region, MappingAccess access); + /** + * Unmaps the mapped memory + * @param queue the command queue + * @param mapping the mapped memory + */ void unmap(CommandQueue queue, ImageMapping mapping); + /** + * 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) { @@ -216,29 +436,60 @@ public interface Image extends OpenCLObject { * Fills the image with the specified color. * Does only work if the image channel is {@link ImageChannelType#FLOAT} * or {@link ImageChannelType#HALF_FLOAT}. - * @param queue - * @param origin - * @param region - * @param color - * @return + * @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 */ Event fillAsync(CommandQueue queue, long[] origin, long[] region, ColorRGBA color); /** * Fills the image with the specified color given as four integer variables. * Does not work if the image channel is {@link ImageChannelType#FLOAT} * or {@link ImageChannelType#HALF_FLOAT}. - * @param queue - * @param origin - * @param region - * @param color - * @return + * @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 */ 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 + */ 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 + */ Event acquireImageForSharingAsync(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. + * @param queue the command queue + * @return the event object + */ Event releaseImageForSharingAsync(CommandQueue queue); + //TODO: add variants of the above two methods that don't create the event object, but release the event immediately } From 1093c639ebb5a0626c7054d9dcd72b58dc01f3d6 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Wed, 27 Apr 2016 09:03:45 +0200 Subject: [PATCH 19/40] finished documentation --- .../src/main/java/com/jme3/opencl/Buffer.java | 1 + .../src/main/java/com/jme3/opencl/Kernel.java | 367 +++++++++++++++++- .../main/java/com/jme3/opencl/LocalMem.java | 71 ---- .../com/jme3/opencl/LocalMemPerElement.java | 71 ---- .../java/com/jme3/opencl/MappingAccess.java | 17 +- .../java/com/jme3/opencl/MemoryAccess.java | 11 +- .../java/com/jme3/opencl/OpenCLException.java | 9 +- .../main/java/com/jme3/opencl/Platform.java | 51 ++- .../main/java/com/jme3/opencl/Program.java | 35 +- .../main/java/com/jme3/opencl/WorkSize.java | 111 ------ .../java/jme3test/opencl/HelloOpenCL.java | 2 +- .../opencl/TestVertexBufferSharing.java | 4 +- .../jme3test/opencl/TestWriteToTexture.java | 2 +- .../com/jme3/opencl/lwjgl/LwjglKernel.java | 7 + 14 files changed, 493 insertions(+), 266 deletions(-) delete mode 100644 jme3-core/src/main/java/com/jme3/opencl/LocalMem.java delete mode 100644 jme3-core/src/main/java/com/jme3/opencl/LocalMemPerElement.java delete mode 100644 jme3-core/src/main/java/com/jme3/opencl/WorkSize.java diff --git a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java index 5e2d56cad..28b76cb72 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java @@ -382,5 +382,6 @@ public abstract class Buffer implements OpenCLObject { * @return the event object */ public abstract Event releaseBufferForSharingAsync(CommandQueue queue); + //TODO: add variants of the above two methods that don't create the event object, but release the event immediately } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java index 4aa87bd1a..257f97662 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java @@ -35,13 +35,61 @@ import com.jme3.math.Quaternion; import com.jme3.math.Vector2f; import com.jme3.math.Vector4f; import java.nio.ByteBuffer; +import java.util.Arrays; /** - * + * Wrapper for an OpenCL kernel, a piece of executable code on the GPU. + *

+ * Terminology:
+ * A Kernel is executed in parallel. In total number of parallel threads, + * called work items, are specified by the global work size (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}. + *
+ * Not all threads can always be executed in parallel because there simply might + * not be enough processor cores. + * Therefore, the concept of a work group 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: shared memory + * 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.
+ * 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. + * + *

+ * There are two ways to launch a kernel:
+ * 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) }.
+ * 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 Sebastian Weiss + * @see Program#createKernel(java.lang.String) */ public abstract class Kernel implements OpenCLObject { + /** + * The current global work size + */ protected final WorkSize globalWorkSize; + /** + * The current local work size + */ protected final WorkSize workGroupSize; protected Kernel() { @@ -49,53 +97,118 @@ public abstract class Kernel implements OpenCLObject { 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); } - public void setWorkGroupSize(int width, int height, int depth) { + /** + * 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); @@ -123,8 +236,27 @@ public abstract class Kernel implements OpenCLObject { public abstract void setArg(int index, Quaternion q); + /** + * 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.
+ * The argument must be a known type: + * {@code LocalMemPerElement, LocalMem, Image, Buffer, byte, short, int, + * long, float, double, Vector2f, Vector4f, Quaternion} + * @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); @@ -163,8 +295,29 @@ public abstract class Kernel implements OpenCLObject { } } + /** + * Launches the kernel with the current global work size, work group size + * and arguments. + * @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); + /** + * 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(); @@ -172,6 +325,14 @@ public abstract class Kernel implements OpenCLObject { return Run(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); @@ -181,5 +342,205 @@ public abstract class Kernel implements OpenCLObject { } //TODO: add variants of the above three methods that don't create the event object, but release the event immediately + + /** + * 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 Sebastian Weiss + */ + 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; + } + } } diff --git a/jme3-core/src/main/java/com/jme3/opencl/LocalMem.java b/jme3-core/src/main/java/com/jme3/opencl/LocalMem.java deleted file mode 100644 index 71a2c8876..000000000 --- a/jme3-core/src/main/java/com/jme3/opencl/LocalMem.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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; - -/** - * A placeholder for kernel launches representing local kernel memory - * @author Sebastian Weiss - */ -public final class LocalMem { - private int size; - - public LocalMem(int size) { - 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; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/opencl/LocalMemPerElement.java b/jme3-core/src/main/java/com/jme3/opencl/LocalMemPerElement.java deleted file mode 100644 index 287eb1f4d..000000000 --- a/jme3-core/src/main/java/com/jme3/opencl/LocalMemPerElement.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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; - -/** - * A placeholder for kernel launches representing local kernel memory per thread - * @author Sebastian Weiss - */ -public final class LocalMemPerElement { - private int size; - - public LocalMemPerElement(int size) { - 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; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/opencl/MappingAccess.java b/jme3-core/src/main/java/com/jme3/opencl/MappingAccess.java index 0f1d3bced..07b89970d 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/MappingAccess.java +++ b/jme3-core/src/main/java/com/jme3/opencl/MappingAccess.java @@ -32,12 +32,27 @@ package com.jme3.opencl; /** - * Specifies the access flags when mapping a {@link Buffer} object. + * 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 Sebastian Weiss */ 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 } diff --git a/jme3-core/src/main/java/com/jme3/opencl/MemoryAccess.java b/jme3-core/src/main/java/com/jme3/opencl/MemoryAccess.java index 0d03791ef..47bf9f75e 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/MemoryAccess.java +++ b/jme3-core/src/main/java/com/jme3/opencl/MemoryAccess.java @@ -32,12 +32,21 @@ package com.jme3.opencl; /** - * Specifies how a buffer object can be accessed + * Specifies how a buffer object can be accessed by the kernel. * @author Sebastian Weiss * @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 } diff --git a/jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java b/jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java index 5cfe47a9a..75ffe52ca 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java +++ b/jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java @@ -32,10 +32,14 @@ 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 Sebastian Weiss */ public class OpenCLException extends RuntimeException { + private static final long serialVersionUID = 8471229972153694848L; private final int errorCode; @@ -63,6 +67,9 @@ public class OpenCLException extends RuntimeException { this.errorCode = errorCode; } + /** + * @return the error code + */ public int getErrorCode() { return errorCode; } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Platform.java b/jme3-core/src/main/java/com/jme3/opencl/Platform.java index 0d5b636ac..fae1bf57f 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Platform.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Platform.java @@ -35,26 +35,73 @@ 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}.
+ * This class is mostly used within {@link PlatformChooser}. + * * @author Sebastian Weiss */ public interface Platform { + /** + * @return the list of available devices for this platform + */ List 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 getExtensions(); - } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Program.java b/jme3-core/src/main/java/com/jme3/opencl/Program.java index 91f588e79..f9ecc5516 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Program.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Program.java @@ -32,15 +32,48 @@ package com.jme3.opencl; /** - * + * A wrapper for an OpenCL program. A program is created from kernel source code, + * manages the build process and creates the kernels. + *

+ * 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 Sebastian Weiss */ public interface Program extends OpenCLObject { + /** + * Builds this program with the specified argument string. + * Please see the official OpenCL specification for a definition of + * all supported arguments + * @param args the compilation arguments + * @throws KernelCompilationException if the compilation fails + * @see #build() + */ void build(String args) throws KernelCompilationException; + /** + * Builds this program without additional arguments + * @throws KernelCompilationException if the compilation fails + * @see #build(java.lang.String) + */ void build() throws KernelCompilationException; + /** + * 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 + */ Kernel createKernel(String name); + + /** + * Creates all available kernels in this program. + * The names of the kernels can then by queried by {@link Kernel#getName() }. + * @return an array of all kernels + */ Kernel[] createAllKernels(); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/WorkSize.java b/jme3-core/src/main/java/com/jme3/opencl/WorkSize.java deleted file mode 100644 index 9a923a42f..000000000 --- a/jme3-core/src/main/java/com/jme3/opencl/WorkSize.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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.Arrays; - -/** - * The work size (global and local) for executing a kernel - * @author Sebastian Weiss - */ -public final class WorkSize { - private int dimension; - private long[] sizes; - - public WorkSize(int dimension, long... sizes) - { - set(dimension, sizes); - } - - public WorkSize() { - this(1, 1, 1, 1); - } - public WorkSize(long size) { - this(1, size, 1, 1); - } - public WorkSize(long width, long height) { - this(2, width, height, 1); - } - 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; - } - - -} diff --git a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java index e697dc584..f4427bb4f 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java +++ b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java @@ -181,7 +181,7 @@ public class HelloOpenCL extends SimpleApplication { int size = 256+128; Buffer buffer = clContext.createBuffer(size*4); float value = 5; - Event event = kernel.Run1(clQueue, new WorkSize(buffer.getSize() / 4), buffer, value); + Event event = kernel.Run1(clQueue, new com.jme3.opencl.Kernel.WorkSize(buffer.getSize() / 4), buffer, value); event.waitForFinished(); //check if filled diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java index 6b251641c..1f175bd2f 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java @@ -56,7 +56,7 @@ public class TestVertexBufferSharing extends SimpleApplication { private Geometry geom; private Buffer buffer; private Kernel kernel; - private WorkSize ws; + private com.jme3.opencl.Kernel.WorkSize ws; private float time; public static void main(String[] args){ @@ -123,7 +123,7 @@ public class TestVertexBufferSharing extends SimpleApplication { //bind vertex buffer to OpenCL VertexBuffer vb = geom.getMesh().getBuffer(VertexBuffer.Type.Position); buffer = clContext.bindVertexBuffer(vb, MemoryAccess.READ_WRITE); - ws = new WorkSize(geom.getMesh().getVertexCount()); + ws = new com.jme3.opencl.Kernel.WorkSize(geom.getMesh().getVertexCount()); } private void updateOpenCL(float tpf) { //advect time diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java index 2f583ea61..296f2062c 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java @@ -137,7 +137,7 @@ public class TestWriteToTexture extends SimpleApplication implements AnalogListe //no need to wait for the returned event, since the kernel implicitely waits for it (same command queue) //execute kernel - kernel.Run1(clQueue, new WorkSize(settings.getWidth(), settings.getHeight()), texCL, C, 16); + kernel.Run1(clQueue, new com.jme3.opencl.Kernel.WorkSize(settings.getWidth(), settings.getHeight()), texCL, C, 16); //release resource texCL.releaseImageForSharingAsync(clQueue); diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java index 19d536e2a..e1260d09b 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java @@ -40,6 +40,7 @@ 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; /** @@ -69,6 +70,12 @@ public class LwjglKernel extends Kernel { 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]); From 7fc740285564ec33459fe0e502ca770981b82e0b Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Wed, 27 Apr 2016 10:30:35 +0200 Subject: [PATCH 20/40] changed author name --- jme3-core/src/main/java/com/jme3/opencl/Buffer.java | 4 ++-- jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java | 2 +- jme3-core/src/main/java/com/jme3/opencl/Context.java | 2 +- .../src/main/java/com/jme3/opencl/DefaultPlatformChooser.java | 2 +- jme3-core/src/main/java/com/jme3/opencl/Device.java | 2 +- jme3-core/src/main/java/com/jme3/opencl/Event.java | 2 +- jme3-core/src/main/java/com/jme3/opencl/Image.java | 2 +- jme3-core/src/main/java/com/jme3/opencl/Kernel.java | 4 ++-- .../main/java/com/jme3/opencl/KernelCompilationException.java | 2 +- jme3-core/src/main/java/com/jme3/opencl/MappingAccess.java | 2 +- jme3-core/src/main/java/com/jme3/opencl/MemoryAccess.java | 2 +- jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java | 2 +- jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java | 2 +- .../src/main/java/com/jme3/opencl/OpenCLObjectManager.java | 2 +- jme3-core/src/main/java/com/jme3/opencl/Platform.java | 2 +- jme3-core/src/main/java/com/jme3/opencl/PlatformChooser.java | 2 +- jme3-core/src/main/java/com/jme3/opencl/Program.java | 2 +- jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java | 2 +- .../main/java/jme3test/opencl/TestVertexBufferSharing.java | 2 +- .../src/main/java/jme3test/opencl/TestWriteToTexture.java | 2 +- .../src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java | 2 +- .../main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java | 2 +- .../src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java | 2 +- .../src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java | 2 +- .../src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java | 2 +- .../src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java | 2 +- .../src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java | 2 +- .../src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java | 2 +- .../src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java | 2 +- jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java | 2 +- 30 files changed, 32 insertions(+), 32 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java index 28b76cb72..5bb474e36 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java @@ -45,7 +45,7 @@ import java.nio.ByteBuffer; * and have the prefix -Async in their name. * * @see Context#createBuffer(long, com.jme3.opencl.MemoryAccess) - * @author Sebastian Weiss + * @author shaman */ public abstract class Buffer implements OpenCLObject { @@ -316,7 +316,7 @@ public abstract class Buffer implements OpenCLObject { * 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 Sebastian Weiss + * @author shaman */ public static class AsyncMapping { diff --git a/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java index 761df702a..3fb5bcf6f 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java +++ b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java @@ -40,7 +40,7 @@ package com.jme3.opencl; * 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 Sebastian Weiss + * @author shaman */ public interface CommandQueue extends OpenCLObject { diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index e108ad729..5dbfa961c 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -61,7 +61,7 @@ import java.util.logging.Logger; *

  • Created buffers and images shared with OpenGL vertex buffers, textures and renderbuffers
  • *
  • Create program objects from source code and source files
  • * - * @author Sebastian Weiss + * @author shaman */ public abstract class Context implements OpenCLObject { private static final Logger LOG = Logger.getLogger(Context.class.getName()); diff --git a/jme3-core/src/main/java/com/jme3/opencl/DefaultPlatformChooser.java b/jme3-core/src/main/java/com/jme3/opencl/DefaultPlatformChooser.java index 70583a367..8f8a53505 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/DefaultPlatformChooser.java +++ b/jme3-core/src/main/java/com/jme3/opencl/DefaultPlatformChooser.java @@ -39,7 +39,7 @@ 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 Sebastian Weiss + * @author shaman */ public class DefaultPlatformChooser implements PlatformChooser { private static final Logger LOG = Logger.getLogger(DefaultPlatformChooser.class.getName()); diff --git a/jme3-core/src/main/java/com/jme3/opencl/Device.java b/jme3-core/src/main/java/com/jme3/opencl/Device.java index aaa349d58..d34854c0c 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Device.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Device.java @@ -42,7 +42,7 @@ import java.util.Collection; *

    * This class is used to query the capabilities of the underlying device. * - * @author Sebastian Weiss + * @author shaman */ public interface Device { diff --git a/jme3-core/src/main/java/com/jme3/opencl/Event.java b/jme3-core/src/main/java/com/jme3/opencl/Event.java index 4e5400459..5399a97ef 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Event.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Event.java @@ -36,7 +36,7 @@ package com.jme3.opencl; * 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 Sebastian Weiss + * @author shaman */ public interface Event extends OpenCLObject { diff --git a/jme3-core/src/main/java/com/jme3/opencl/Image.java b/jme3-core/src/main/java/com/jme3/opencl/Image.java index 368b9a62d..92545021a 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Image.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Image.java @@ -72,7 +72,7 @@ import java.util.Objects; * 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 Sebastian Weiss + * @author shaman */ public interface Image extends OpenCLObject { diff --git a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java index 257f97662..c7482a937 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java @@ -79,7 +79,7 @@ import java.util.Arrays; * {@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 Sebastian Weiss + * @author shaman * @see Program#createKernel(java.lang.String) */ public abstract class Kernel implements OpenCLObject { @@ -441,7 +441,7 @@ public abstract class Kernel implements OpenCLObject { /** * The work size (global and local) for executing a kernel - * @author Sebastian Weiss + * @author shaman */ public static final class WorkSize { diff --git a/jme3-core/src/main/java/com/jme3/opencl/KernelCompilationException.java b/jme3-core/src/main/java/com/jme3/opencl/KernelCompilationException.java index 478f62c2c..a0e20c9e5 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/KernelCompilationException.java +++ b/jme3-core/src/main/java/com/jme3/opencl/KernelCompilationException.java @@ -36,7 +36,7 @@ package com.jme3.opencl; * when the compilation failed. * The error log returned by {@link #getLog() } contains detailed information * where the error occured. - * @author Sebastian Weiss + * @author shaman */ public class KernelCompilationException extends OpenCLException { diff --git a/jme3-core/src/main/java/com/jme3/opencl/MappingAccess.java b/jme3-core/src/main/java/com/jme3/opencl/MappingAccess.java index 07b89970d..121c6c8cb 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/MappingAccess.java +++ b/jme3-core/src/main/java/com/jme3/opencl/MappingAccess.java @@ -35,7 +35,7 @@ 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 Sebastian Weiss + * @author shaman */ public enum MappingAccess { /** diff --git a/jme3-core/src/main/java/com/jme3/opencl/MemoryAccess.java b/jme3-core/src/main/java/com/jme3/opencl/MemoryAccess.java index 47bf9f75e..d5071665e 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/MemoryAccess.java +++ b/jme3-core/src/main/java/com/jme3/opencl/MemoryAccess.java @@ -33,7 +33,7 @@ package com.jme3.opencl; /** * Specifies how a buffer object can be accessed by the kernel. - * @author Sebastian Weiss + * @author shaman * @see Buffer */ public enum MemoryAccess { diff --git a/jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java b/jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java index 75ffe52ca..fd0836ac9 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java +++ b/jme3-core/src/main/java/com/jme3/opencl/OpenCLException.java @@ -36,7 +36,7 @@ package com.jme3.opencl; * 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 Sebastian Weiss + * @author shaman */ public class OpenCLException extends RuntimeException { private static final long serialVersionUID = 8471229972153694848L; diff --git a/jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java index e0b542e54..6ee0bc121 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java +++ b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java @@ -33,7 +33,7 @@ package com.jme3.opencl; /** * - * @author Sebastian Weiss + * @author shaman */ public interface OpenCLObject { diff --git a/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java index 7eebf4bb8..7895781d3 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java +++ b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java @@ -39,7 +39,7 @@ import java.util.logging.Logger; /** * - * @author Sebastian Weiss + * @author shaman */ public class OpenCLObjectManager { private static final Logger LOG = Logger.getLogger(OpenCLObjectManager.class.getName()); diff --git a/jme3-core/src/main/java/com/jme3/opencl/Platform.java b/jme3-core/src/main/java/com/jme3/opencl/Platform.java index fae1bf57f..10b3fd466 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Platform.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Platform.java @@ -40,7 +40,7 @@ import java.util.List; * create the {@link Context}.
    * This class is mostly used within {@link PlatformChooser}. * - * @author Sebastian Weiss + * @author shaman */ public interface Platform { diff --git a/jme3-core/src/main/java/com/jme3/opencl/PlatformChooser.java b/jme3-core/src/main/java/com/jme3/opencl/PlatformChooser.java index 51453cbe5..a1646df25 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/PlatformChooser.java +++ b/jme3-core/src/main/java/com/jme3/opencl/PlatformChooser.java @@ -37,7 +37,7 @@ import java.util.List; /** * This SPI is called on startup to specify which platform and which devices * are used for context creation. - * @author Sebastian Weiss + * @author shaman * @see AppSettings#setOpenCLPlatformChooser(java.lang.Class) */ public interface PlatformChooser { diff --git a/jme3-core/src/main/java/com/jme3/opencl/Program.java b/jme3-core/src/main/java/com/jme3/opencl/Program.java index f9ecc5516..8774b7c45 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Program.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Program.java @@ -40,7 +40,7 @@ package com.jme3.opencl; * * @see Context#createProgramFromSourceCode(java.lang.String) * @see #createKernel(java.lang.String) - * @author Sebastian Weiss + * @author shaman */ public interface Program extends OpenCLObject { diff --git a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java index f4427bb4f..a4db6dd64 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java +++ b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java @@ -48,7 +48,7 @@ import java.util.logging.Logger; /** * Simple test checking if the basic functions of the OpenCL wrapper work - * @author Sebastian Weiss + * @author shaman */ public class HelloOpenCL extends SimpleApplication { private static final Logger LOG = Logger.getLogger(HelloOpenCL.class.getName()); diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java index 1f175bd2f..76c2e01f4 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java @@ -45,7 +45,7 @@ import java.util.logging.Logger; /** * This test class tests the capability to read and modify an OpenGL vertex buffer. * - * @author Sebastian Weiss + * @author shaman */ public class TestVertexBufferSharing extends SimpleApplication { private static final Logger LOG = Logger.getLogger(TestVertexBufferSharing.class.getName()); diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java index 296f2062c..43a6c64fe 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java @@ -49,7 +49,7 @@ 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. * - * @author Sebastian Weiss + * @author shaman */ public class TestWriteToTexture extends SimpleApplication implements AnalogListener, ActionListener { private static final Logger LOG = Logger.getLogger(TestWriteToTexture.class.getName()); diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java index 7b9adb4ba..60277427a 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java @@ -37,7 +37,7 @@ import org.lwjgl.opencl.*; /** * - * @author Sebastian Weiss + * @author shaman */ public class LwjglBuffer extends Buffer { diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java index 55392157d..a0fd04ddc 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java @@ -38,7 +38,7 @@ import org.lwjgl.opencl.CLCommandQueue; /** * - * @author Sebastian Weiss + * @author shaman */ public class LwjglCommandQueue implements CommandQueue { diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java index 13af4946f..ad3450f8f 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java @@ -49,7 +49,7 @@ import org.lwjgl.opengl.*; /** * - * @author Sebastian Weiss + * @author shaman */ public class LwjglContext extends Context { private static final Logger LOG = Logger.getLogger(LwjglContext.class.getName()); diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java index b8985d6f5..7811e3a00 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java @@ -41,7 +41,7 @@ import org.lwjgl.opencl.CLDevice; /** * - * @author Sebastian Weiss + * @author shaman */ public final class LwjglDevice implements Device { diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java index 2819c7bf9..5055ac7af 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java @@ -39,7 +39,7 @@ import org.lwjgl.opencl.CLEvent; /** * - * @author Sebastian Weiss + * @author shaman */ public class LwjglEvent implements Event { private static final Logger LOG = Logger.getLogger(LwjglEvent.class.getName()); diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java index 52be48d94..904b3ca0b 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java @@ -41,7 +41,7 @@ import org.lwjgl.opencl.api.CLImageFormat; /** * - * @author Sebastian Weiss + * @author shaman */ public class LwjglImage implements Image { private static final Logger LOG = Logger.getLogger(LwjglImage.class.getName()); diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java index e1260d09b..21f165df6 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java @@ -45,7 +45,7 @@ import org.lwjgl.opencl.CLKernel; /** * - * @author Sebastian Weiss + * @author shaman */ public class LwjglKernel extends Kernel { diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java index 7982ff2de..7d22d0aca 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java @@ -43,7 +43,7 @@ import org.lwjgl.opencl.CLPlatform; /** * - * @author Sebastian Weiss + * @author shaman */ public final class LwjglPlatform implements Platform { diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java index 2ce274754..a926c3d14 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java @@ -42,7 +42,7 @@ import org.lwjgl.opencl.*; /** * - * @author Sebastian Weiss + * @author shaman */ public class LwjglProgram implements Program { private static final Logger LOG = Logger.getLogger(LwjglProgram.class.getName()); diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java index 07e36506e..082acb3d2 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java @@ -46,7 +46,7 @@ import org.lwjgl.opencl.*; /** * - * @author Sebastian Weiss + * @author shaman */ public class Utils { private static final Logger LOG = Logger.getLogger(Utils.class.getName()); From a26e526945aba00220a99fb0d734b04257b3163b Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Sun, 1 May 2016 18:38:48 +0200 Subject: [PATCH 21/40] Added an experimental Jocl binding. Note that Jogamp's Jocl only supports OpenCL1.1, some methods will throw an UnsupportedOperationException. --- .../java/jme3test/opencl/HelloOpenCL.java | 7 +- .../opencl/TestVertexBufferSharing.java | 1 + .../jme3test/opencl/TestWriteToTexture.java | 3 +- jme3-jogl/build.gradle | 1 + .../java/com/jme3/opencl/jocl/JoclBuffer.java | 225 ++++++++ .../jme3/opencl/jocl/JoclCommandQueue.java | 90 +++ .../com/jme3/opencl/jocl/JoclContext.java | 249 ++++++++ .../java/com/jme3/opencl/jocl/JoclDevice.java | 302 ++++++++++ .../java/com/jme3/opencl/jocl/JoclEvent.java | 103 ++++ .../java/com/jme3/opencl/jocl/JoclImage.java | 533 ++++++++++++++++++ .../java/com/jme3/opencl/jocl/JoclKernel.java | 261 +++++++++ .../com/jme3/opencl/jocl/JoclPlatform.java | 127 +++++ .../com/jme3/opencl/jocl/JoclProgram.java | 152 +++++ .../main/java/com/jme3/opencl/jocl/Utils.java | 160 ++++++ .../com/jme3/system/jogl/JoglContext.java | 98 ++++ .../com/jme3/opencl/lwjgl/LwjglImage.java | 9 +- 16 files changed, 2313 insertions(+), 8 deletions(-) create mode 100644 jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java create mode 100644 jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclCommandQueue.java create mode 100644 jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java create mode 100644 jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclDevice.java create mode 100644 jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclEvent.java create mode 100644 jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java create mode 100644 jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java create mode 100644 jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclPlatform.java create mode 100644 jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java create mode 100644 jme3-jogl/src/main/java/com/jme3/opencl/jocl/Utils.java diff --git a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java index a4db6dd64..4100fd92b 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java +++ b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java @@ -58,6 +58,7 @@ public class HelloOpenCL extends SimpleApplication { 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 } @@ -208,7 +209,11 @@ public class HelloOpenCL extends SimpleApplication { //query supported formats for (MemoryAccess ma : MemoryAccess.values()) { for (Image.ImageType type : Image.ImageType.values()) { - System.out.println("Formats for "+ma+" and "+type+": "+Arrays.toString(clContext.querySupportedFormats(ma, type))); + try { + System.out.println("Formats for " + ma + " and " + type + ": " + Arrays.toString(clContext.querySupportedFormats(ma, type))); + } catch (UnsupportedOperationException e) { + LOG.warning(e.getLocalizedMessage()); + } } } diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java index 76c2e01f4..06e2684dc 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java @@ -64,6 +64,7 @@ public class TestVertexBufferSharing extends SimpleApplication { 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 } diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java index 43a6c64fe..5230fb69d 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java @@ -63,13 +63,13 @@ public class TestWriteToTexture extends SimpleApplication implements AnalogListe private Vector2f C; private Image texCL; private boolean dragging; - private int gcCounter; 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 } @@ -87,7 +87,6 @@ public class TestWriteToTexture extends SimpleApplication implements AnalogListe guiNode.attachChild(pic); initCounter = 0; - gcCounter = 0; flyCam.setEnabled(false); inputManager.setCursorVisible(true); diff --git a/jme3-jogl/build.gradle b/jme3-jogl/build.gradle index df24c15ec..b71be027a 100644 --- a/jme3-jogl/build.gradle +++ b/jme3-jogl/build.gradle @@ -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' } diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java new file mode 100644 index 000000000..773b581b1 --- /dev/null +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java @@ -0,0 +1,225 @@ +/* + * 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) { + this.id = id; + this.cl = CLPlatform.getLowLevelCLInterface(); + OpenCLObjectManager.getInstance().registerObject(this); + } + + @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(); + 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 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 ObjectReleaser getReleaser() { + return new ReleaserImpl(id); + } + 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"); + } + } + + } +} diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclCommandQueue.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclCommandQueue.java new file mode 100644 index 000000000..790bc152b --- /dev/null +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclCommandQueue.java @@ -0,0 +1,90 @@ +/* + * 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 implements CommandQueue { + + final CL cl; + final long id; + + public JoclCommandQueue(long id) { + this.id = id; + this.cl = CLPlatform.getLowLevelCLInterface(); + OpenCLObjectManager.getInstance().registerObject(this); + } + + @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"); + } + + @Override + public ObjectReleaser getReleaser() { + return new ReleaserImpl(id, cl); + } + private static class ReleaserImpl implements ObjectReleaser { + private long id; + private CLCommandQueueBinding cl; + + private ReleaserImpl(long id, CLCommandQueueBinding cl) { + this.id = id; + this.cl = cl; + } + + @Override + public void release() { + if (id != 0) { + int ret = cl.clReleaseCommandQueue(id); + id = 0; + Utils.reportError(ret, "clReleaseCommandQueue"); + } + } + } +} diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java new file mode 100644 index 000000000..4e9b6e920 --- /dev/null +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java @@ -0,0 +1,249 @@ +/* + * 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; +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.nio.IntBuffer; +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 devices; + + public JoclContext(CLContext context, List devices) { + this.context = context; + this.id = context.ID; + this.cl = context.getCL(); + this.devices = devices; + OpenCLObjectManager.getInstance().registerObject(this); + } + + public CLContext getContext() { + return context; + } + + @Override + public List 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 devices; + private ReleaserImpl(long id, List 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"); + } + } + + } +} diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclDevice.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclDevice.java new file mode 100644 index 000000000..d4d9b08e1 --- /dev/null +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclDevice.java @@ -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 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 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 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 = CLPlatform.getLowLevelCLInterface().clReleaseKernel(kernel); + kernel = 0; + Utils.reportError(ret, "clReleaseKernel"); + } + } + } +} diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclPlatform.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclPlatform.java new file mode 100644 index 000000000..56d551180 --- /dev/null +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclPlatform.java @@ -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 devices; + + public JoclPlatform(CLPlatform platform) { + this.platform = platform; + } + + public CLPlatform getPlatform() { + return platform; + } + + @Override + public List 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 getExtensions() { + return platform.getExtensions(); + } + +} diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java new file mode 100644 index 000000000..dcc32014a --- /dev/null +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java @@ -0,0 +1,152 @@ +/* + * 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.Kernel; +import com.jme3.opencl.KernelCompilationException; +import com.jme3.opencl.OpenCLObjectManager; +import com.jme3.opencl.Program; +import com.jogamp.common.nio.PointerBuffer; +import com.jogamp.opencl.CLPlatform; +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; +import static com.jogamp.opencl.CLException.newException; +import static com.jogamp.opencl.llb.CL.CL_SUCCESS; +/** + * + * @author shaman + */ +public class JoclProgram implements 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) { + this.program = program; + this.context = context; + this.cl = CLPlatform.getLowLevelCLInterface(); + OpenCLObjectManager.getInstance().registerObject(this); + } + + @Override + public void build(String args) throws KernelCompilationException { + int ret = cl.clBuildProgram(program, 0, null, 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()); + } + } + + @Override + public void build() throws KernelCompilationException { + build(""); + } + + 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 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); + } + } + +} diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java index 602298bb9..12c1d10cb 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java @@ -36,6 +36,11 @@ 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; @@ -56,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; @@ -65,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 { @@ -218,8 +229,95 @@ public abstract class JoglContext implements JmeContext { } } + @SuppressWarnings("unchecked") protected void initOpenCL() { logger.info("Initialize OpenCL with JOGL"); + + //load platforms and devices + StringBuilder platformInfos = new StringBuilder(); + ArrayList platforms = new ArrayList(); + for (CLPlatform p : CLPlatform.listCLPlatforms()) { + platforms.add(new JoclPlatform(p)); + } + platformInfos.append("Available OpenCL platforms:"); + for (int i=0; i devices = platform.getDevices(); + platformInfos.append("\n * Available devices:"); + for (int j=0; j choosenDevices = chooser.chooseDevices(platforms); + List 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) choosenDevices); + } catch (Exception ex) { + logger.log(Level.SEVERE, "Unable to create OpenCL context", ex); + return; + } + + logger.info("OpenCL context created"); } public void internalCreate() { diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java index 904b3ca0b..1ed59641b 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java @@ -419,9 +419,7 @@ public class LwjglImage implements Image { Utils.pointerBuffers[1], Utils.pointerBuffers[2], Utils.pointerBuffers[3], Utils.pointerBuffers[4], null, null, 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))); + return new ImageMapping(buf, Utils.pointerBuffers[3].get(0), Utils.pointerBuffers[4].get(0)); } @Override @@ -441,9 +439,10 @@ public class LwjglImage implements Image { 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, null, Utils.errorBuffer); + Utils.pointerBuffers[3], Utils.pointerBuffers[4], null, Utils.pointerBuffers[0], Utils.errorBuffer); Utils.checkError(Utils.errorBuffer, "clEnqueueMapBuffer"); - return new ImageMapping(buf, Utils.pointerBuffers[3].get(0), Utils.pointerBuffers[4].get(0)); + 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 From 4be60130689522eba4cbf36f89024f53b527bc26 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Mon, 2 May 2016 08:30:00 +0200 Subject: [PATCH 22/40] reworked releasing system. Now one has to either release a native OpenCLObject manually with release() or register it for automatic garbage collection using register(). These changes greatly improve the performance by reducing the load on the OpenCLObjectManager. --- .../com/jme3/opencl/AbstractOpenCLObject.java | 62 +++++++++++++++++++ .../src/main/java/com/jme3/opencl/Buffer.java | 6 +- .../java/com/jme3/opencl/CommandQueue.java | 10 ++- .../main/java/com/jme3/opencl/Context.java | 6 +- .../src/main/java/com/jme3/opencl/Event.java | 16 +++-- .../src/main/java/com/jme3/opencl/Image.java | 52 +++++++++------- .../src/main/java/com/jme3/opencl/Kernel.java | 5 +- .../java/com/jme3/opencl/OpenCLObject.java | 34 +++++++++- .../com/jme3/opencl/OpenCLObjectManager.java | 7 ++- .../main/java/com/jme3/opencl/Program.java | 18 ++++-- .../java/jme3test/opencl/HelloOpenCL.java | 19 +++++- .../opencl/TestVertexBufferSharing.java | 10 ++- .../jme3test/opencl/TestWriteToTexture.java | 11 +++- .../java/com/jme3/opencl/jocl/JoclBuffer.java | 6 +- .../jme3/opencl/jocl/JoclCommandQueue.java | 14 ++--- .../com/jme3/opencl/jocl/JoclContext.java | 8 +-- .../java/com/jme3/opencl/jocl/JoclEvent.java | 11 ++-- .../java/com/jme3/opencl/jocl/JoclImage.java | 8 +-- .../java/com/jme3/opencl/jocl/JoclKernel.java | 6 +- .../com/jme3/opencl/jocl/JoclProgram.java | 13 +--- .../com/jme3/opencl/lwjgl/LwjglBuffer.java | 6 +- .../jme3/opencl/lwjgl/LwjglCommandQueue.java | 8 +-- .../com/jme3/opencl/lwjgl/LwjglContext.java | 6 +- .../com/jme3/opencl/lwjgl/LwjglEvent.java | 20 ++---- .../com/jme3/opencl/lwjgl/LwjglImage.java | 8 +-- .../com/jme3/opencl/lwjgl/LwjglKernel.java | 2 +- .../com/jme3/opencl/lwjgl/LwjglProgram.java | 13 +--- 27 files changed, 230 insertions(+), 155 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/opencl/AbstractOpenCLObject.java diff --git a/jme3-core/src/main/java/com/jme3/opencl/AbstractOpenCLObject.java b/jme3-core/src/main/java/com/jme3/opencl/AbstractOpenCLObject.java new file mode 100644 index 000000000..fce0f481d --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/AbstractOpenCLObject.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009-2016 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.opencl; + +/** + * Abstract implementation of {@link OpenCLObject} providing the release + * mechanisms. + * @author Sebastian Weiss + */ +public abstract class AbstractOpenCLObject implements OpenCLObject { + + protected final ObjectReleaser releaser; + protected AbstractOpenCLObject(ObjectReleaser releaser) { + this.releaser = releaser; + } + @Override + public void register() { + OpenCLObjectManager.getInstance().registerObject(this); + } + @Override + public void release() { + releaser.release(); + } + @Override + @SuppressWarnings("FinalizeDeclaration") + protected void finalize() throws Throwable { + release(); + } + @Override + public ObjectReleaser getReleaser() { + return releaser; + } +} diff --git a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java index 5bb474e36..66ce0c8f7 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java @@ -47,8 +47,12 @@ import java.nio.ByteBuffer; * @see Context#createBuffer(long, com.jme3.opencl.MemoryAccess) * @author shaman */ -public abstract class Buffer implements OpenCLObject { +public abstract class Buffer extends AbstractOpenCLObject { + protected Buffer(ObjectReleaser releaser) { + super(releaser); + } + /** * @return the size of the buffer in bytes. * @see Context#createBuffer(long) diff --git a/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java index 3fb5bcf6f..6d54237f9 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java +++ b/jme3-core/src/main/java/com/jme3/opencl/CommandQueue.java @@ -42,8 +42,12 @@ package com.jme3.opencl; * and all commands are sent to this device. * @author shaman */ -public interface CommandQueue extends OpenCLObject { +public abstract class CommandQueue extends AbstractOpenCLObject { + protected CommandQueue(ObjectReleaser releaser) { + super(releaser); + } + /** * Issues all previously queued OpenCL commands in command_queue to the * device associated with command queue. Flush only guarantees that all @@ -51,7 +55,7 @@ public interface CommandQueue extends OpenCLObject { * appropriate device. There is no guarantee that they will be complete * after flush returns. */ - void flush(); + public abstract void flush(); /** * Blocks until all previously queued OpenCL commands in command queue are @@ -59,6 +63,6 @@ public interface CommandQueue extends OpenCLObject { * return until all previously queued commands in command queue have been * processed and completed. Finish is also a synchronization point. */ - void finish(); + public abstract void finish(); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index 5dbfa961c..10dde71fc 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -63,9 +63,13 @@ import java.util.logging.Logger; * * @author shaman */ -public abstract class Context implements OpenCLObject { +public abstract class Context extends AbstractOpenCLObject { private static final Logger LOG = Logger.getLogger(Context.class.getName()); + protected Context(ObjectReleaser releaser) { + super(releaser); + } + /** * Returns all available devices for this context. * These devices all belong to the same {@link Platform}. diff --git a/jme3-core/src/main/java/com/jme3/opencl/Event.java b/jme3-core/src/main/java/com/jme3/opencl/Event.java index 5399a97ef..44ea3da16 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Event.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Event.java @@ -38,16 +38,22 @@ package com.jme3.opencl; * is done. * @author shaman */ -public interface Event extends OpenCLObject { +public abstract class Event extends AbstractOpenCLObject { + + protected Event(ObjectReleaser releaser) { + super(releaser); + } /** - * Waits until the action has finished (blocking) + * Waits until the action has finished (blocking). + * This automatically releases the event. */ - void waitForFinished(); + public abstract void waitForFinished(); /** - * Tests if the action is completed + * Tests if the action is completed. + * If the action is completed, the event is released. * @return {@code true} if the action is completed */ - boolean isCompleted(); + public abstract boolean isCompleted(); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Image.java b/jme3-core/src/main/java/com/jme3/opencl/Image.java index 92545021a..e58c20f7e 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Image.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Image.java @@ -74,7 +74,7 @@ import java.util.Objects; * * @author shaman */ -public interface Image extends OpenCLObject { +public abstract class Image extends AbstractOpenCLObject { /** * {@code ImageChannelType} describes the size of the channel data type. @@ -245,47 +245,51 @@ memory layout in which channels are stored in the image. } } + + protected Image(ObjectReleaser releaser) { + super(releaser); + } /** * @return the width of the image */ - long getWidth(); + public abstract long getWidth(); /** * @return the height of the image */ - long getHeight(); + public abstract long getHeight(); /** * @return the depth of the image */ - long getDepth(); + public abstract long getDepth(); /** * @return the row pitch when the image was created from a host buffer * @see ImageDescriptor#ImageDescriptor(com.jme3.opencl.Image.ImageType, long, long, long, long, long, long, java.nio.ByteBuffer) */ - long getRowPitch(); + public abstract long getRowPitch(); /** * @return the slice pitch when the image was created from a host buffer * @see ImageDescriptor#ImageDescriptor(com.jme3.opencl.Image.ImageType, long, long, long, long, long, long, java.nio.ByteBuffer) */ - long getSlicePitch(); + public abstract long getSlicePitch(); /** * @return the number of elements in the image array * @see ImageType#IMAGE_1D_ARRAY * @see ImageType#IMAGE_2D_ARRAY */ - long getArraySize(); + public abstract long getArraySize(); /** * @return the image format */ - ImageFormat getImageFormat(); + public abstract ImageFormat getImageFormat(); /** * @return the image type */ - ImageType getImageType(); + public abstract ImageType getImageType(); /** * @return the number of bytes per pixel */ - int getElementSize(); + public abstract int getElementSize(); /** * Performs a blocking read of the image into the specified byte buffer. @@ -298,7 +302,7 @@ memory layout in which channels are stored in the image. * @param slicePitch the slice pitch of the target buffer, must be set to 0 for 1D and 2D images. * If set to 0 for 3D images, the slice pitch is calculated as {@code rowPitch * height} */ - void readImage(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch); + public abstract void readImage(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch); /** * Performs an async/non-blocking read of the image into the specified byte buffer. * @param queue the command queue @@ -311,7 +315,7 @@ memory layout in which channels are stored in the image. * If set to 0 for 3D images, the slice pitch is calculated as {@code rowPitch * height} * @return the event object indicating the status of the operation */ - Event readImageAsync(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch); + public abstract Event readImageAsync(CommandQueue queue, ByteBuffer dest, long[] origin, long[] region, long rowPitch, long slicePitch); /** * Performs a blocking write from the specified byte buffer into the image. @@ -324,7 +328,7 @@ memory layout in which channels are stored in the image. * @param slicePitch the slice pitch of the target buffer, must be set to 0 for 1D and 2D images. * If set to 0 for 3D images, the slice pitch is calculated as {@code rowPitch * height} */ - void writeImage(CommandQueue queue, ByteBuffer src, long[] origin, long[] region, long rowPitch, long slicePitch); + public abstract void writeImage(CommandQueue queue, ByteBuffer src, long[] origin, long[] region, long rowPitch, long slicePitch); /** * Performs an async/non-blocking write from the specified byte buffer into the image. * @param queue the command queue @@ -337,7 +341,7 @@ memory layout in which channels are stored in the image. * If set to 0 for 3D images, the slice pitch is calculated as {@code rowPitch * height} * @return the event object indicating the status of the operation */ - Event writeImageAsync(CommandQueue queue, ByteBuffer src, long[] origin, long[] region, long rowPitch, long slicePitch); + public abstract Event writeImageAsync(CommandQueue queue, ByteBuffer src, long[] origin, long[] region, long rowPitch, long slicePitch); /** * Performs a blocking copy operation from one image to another. @@ -348,7 +352,7 @@ memory layout in which channels are stored in the image. * @param destOrigin the target image origin, see class description for the format * @param region the copied region, see class description for the format */ - void copyTo(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region); + public abstract void copyTo(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region); /** * Performs an async/non-blocking copy operation from one image to another. * Important: Both images must have the same format! @@ -359,7 +363,7 @@ memory layout in which channels are stored in the image. * @param region the copied region, see class description for the format * @return the event object indicating the status of the operation */ - Event copyToAsync(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region); + public abstract Event copyToAsync(CommandQueue queue, Image dest, long[] srcOrigin, long[] destOrigin, long[] region); /** * Maps the image into host memory. @@ -373,7 +377,7 @@ memory layout in which channels are stored in the image. * @return a structure describing the mapped memory * @see #unmap(com.jme3.opencl.CommandQueue, com.jme3.opencl.Image.ImageMapping) */ - ImageMapping map(CommandQueue queue, long[] origin, long[] region, MappingAccess access); + public abstract ImageMapping map(CommandQueue queue, long[] origin, long[] region, MappingAccess access); /** * Non-blocking version of {@link #map(com.jme3.opencl.CommandQueue, long[], long[], com.jme3.opencl.MappingAccess) }. * The returned structure contains the mapped byte buffer and row and slice pitch. @@ -385,13 +389,13 @@ memory layout in which channels are stored in the image. * @return a structure describing the mapped memory * @see #unmap(com.jme3.opencl.CommandQueue, com.jme3.opencl.Image.ImageMapping) */ - ImageMapping mapAsync(CommandQueue queue, long[] origin, long[] region, MappingAccess access); + public abstract ImageMapping mapAsync(CommandQueue queue, long[] origin, long[] region, MappingAccess access); /** * Unmaps the mapped memory * @param queue the command queue * @param mapping the mapped memory */ - void unmap(CommandQueue queue, ImageMapping mapping); + public abstract void unmap(CommandQueue queue, ImageMapping mapping); /** * Describes a mapped region of the image @@ -442,7 +446,7 @@ memory layout in which channels are stored in the image. * @param color the color to fill * @return an event object to detect for the completion */ - Event fillAsync(CommandQueue queue, long[] origin, long[] region, ColorRGBA color); + public abstract Event fillAsync(CommandQueue queue, long[] origin, long[] region, ColorRGBA color); /** * Fills the image with the specified color given as four integer variables. * Does not work if the image channel is {@link ImageChannelType#FLOAT} @@ -453,7 +457,7 @@ memory layout in which channels are stored in the image. * @param color the color to fill, must be an array of length 4 * @return an event object to detect for the completion */ - Event fillAsync(CommandQueue queue, long[] origin, long[] region, int[] color); + public abstract Event fillAsync(CommandQueue queue, long[] origin, long[] region, int[] color); /** * Copies this image into the specified buffer, no format conversion is done. @@ -466,7 +470,7 @@ memory layout in which channels are stored in the image. * @param destOffset an offset into the target buffer * @return the event object to detect the completion of the operation */ - Event copyToBufferAsync(CommandQueue queue, Buffer dest, long[] srcOrigin, long[] srcRegion, long destOffset); + public abstract Event copyToBufferAsync(CommandQueue queue, Buffer dest, long[] srcOrigin, long[] srcRegion, long destOffset); /** * Aquires this image object for using. Only call this method if this image @@ -480,7 +484,7 @@ memory layout in which channels are stored in the image. * @param queue the command queue * @return the event object */ - Event acquireImageForSharingAsync(CommandQueue queue); + public abstract Event acquireImageForSharingAsync(CommandQueue queue); /** * Releases a shared image object. * Call this method after the image object was acquired by @@ -489,7 +493,7 @@ memory layout in which channels are stored in the image. * @param queue the command queue * @return the event object */ - Event releaseImageForSharingAsync(CommandQueue queue); + public abstract Event releaseImageForSharingAsync(CommandQueue queue); //TODO: add variants of the above two methods that don't create the event object, but release the event immediately } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java index c7482a937..82fbf9018 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java @@ -82,7 +82,7 @@ import java.util.Arrays; * @author shaman * @see Program#createKernel(java.lang.String) */ -public abstract class Kernel implements OpenCLObject { +public abstract class Kernel extends AbstractOpenCLObject { /** * The current global work size */ @@ -92,7 +92,8 @@ public abstract class Kernel implements OpenCLObject { */ protected final WorkSize workGroupSize; - protected Kernel() { + protected Kernel(ObjectReleaser releaser) { + super(releaser); this.globalWorkSize = new WorkSize(0); this.workGroupSize = new WorkSize(0); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java index 6ee0bc121..f9d631346 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java +++ b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObject.java @@ -32,14 +32,44 @@ package com.jme3.opencl; /** - * + * Base interface of all native OpenCL objects. + * This interface provides the functionality for savely release the object. * @author shaman */ public interface OpenCLObject { + /** + * Releaser for an {@link OpenCLObject}. + * Implementations of this interface must not hold a reference to the + * {@code OpenCLObject} directly. + */ public static interface ObjectReleaser { + /** + * Releases the native resources of the associated {@link OpenCLObject}. + * This method must be guarded against multiple calls: only the first + * call should release, the next ones must not throw an exception. + */ void release(); } + /** + * Returns the releaser object. Multiple calls should return the same object. + * The ObjectReleaser is used to release the OpenCLObject when it is garbage + * collected. Therefore, the returned object must not hold a reference to + * the OpenCLObject. + * @return the object releaser + */ ObjectReleaser getReleaser(); - + /** + * Releases this native object. + * Should delegate to {@code getReleaser().release()}. + */ + void release(); + /** + * Registers this object for automatic releasing on garbage collection. + * By default, OpenCLObjects are not registered in the + * {@link OpenCLObjectManager}, you have to release it manually + * by calling {@link #release() }. + * Without registering or releasing, a memory leak might occur. + */ + void register(); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java index 7895781d3..1d29a829f 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java +++ b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java @@ -43,8 +43,8 @@ import java.util.logging.Logger; */ public class OpenCLObjectManager { private static final Logger LOG = Logger.getLogger(OpenCLObjectManager.class.getName()); - private static final Level LOG_LEVEL1 = Level.FINER; - private static final Level LOG_LEVEL2 = Level.FINE; + private static final Level LOG_LEVEL1 = Level.INFO; + private static final Level LOG_LEVEL2 = Level.INFO; /** * Call Runtime.getRuntime().gc() every these frames */ @@ -85,6 +85,7 @@ public class OpenCLObjectManager { public void deleteUnusedObjects() { if (activeObjects.isEmpty()) { + LOG.log(LOG_LEVEL2, "no active natives"); return; //nothing to do } @@ -108,7 +109,7 @@ public class OpenCLObjectManager { removed++; } if (removed >= 1) { - LOG.log(LOG_LEVEL2, "NativeObjectManager: {0} native objects were removed from native", removed); + LOG.log(LOG_LEVEL2, "{0} native objects were removed from native", removed); } } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Program.java b/jme3-core/src/main/java/com/jme3/opencl/Program.java index 8774b7c45..3cfe7bf05 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Program.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Program.java @@ -42,8 +42,12 @@ package com.jme3.opencl; * @see #createKernel(java.lang.String) * @author shaman */ -public interface Program extends OpenCLObject { - +public abstract class Program extends AbstractOpenCLObject { + + protected Program(ObjectReleaser releaser) { + super(releaser); + } + /** * Builds this program with the specified argument string. * Please see the official OpenCL specification for a definition of @@ -52,13 +56,15 @@ public interface Program extends OpenCLObject { * @throws KernelCompilationException if the compilation fails * @see #build() */ - void build(String args) throws KernelCompilationException; + public abstract void build(String args) throws KernelCompilationException; /** * Builds this program without additional arguments * @throws KernelCompilationException if the compilation fails * @see #build(java.lang.String) */ - void build() throws KernelCompilationException; + public void build() throws KernelCompilationException { + build(""); + } /** * Creates the kernel with the specified name. @@ -67,13 +73,13 @@ public interface Program extends OpenCLObject { * @throws OpenCLException if the kernel was not found or some other * error occured */ - Kernel createKernel(String name); + public abstract Kernel createKernel(String name); /** * Creates all available kernels in this program. * The names of the kernels can then by queried by {@link Kernel#getName() }. * @return an array of all kernels */ - Kernel[] createAllKernels(); + public abstract Kernel[] createAllKernels(); } diff --git a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java index 4100fd92b..e08802785 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java +++ b/jme3-examples/src/main/java/jme3test/opencl/HelloOpenCL.java @@ -85,6 +85,8 @@ public class HelloOpenCL extends SimpleApplication { str.append("\n Kernel: ").append(testKernel(clContext, clQueue)); str.append("\n Images: ").append(testImages(clContext, clQueue)); + clQueue.release(); + BitmapText txt1 = new BitmapText(fnt); txt1.setText(str.toString()); txt1.setLocalTranslation(5, settings.getHeight() - 5, 0); @@ -159,6 +161,10 @@ public class HelloOpenCL extends SimpleApplication { assertEquals((byte) (i+low), b, "Wrong byte read"); } + //release + b1.release(); + b2.release(); + } catch (AssertionError ex) { LOG.log(Level.SEVERE, "Buffer test failed with an assertion error"); return false; @@ -193,6 +199,11 @@ public class HelloOpenCL extends SimpleApplication { assertEquals(value, v, "Buffer filled with the wrong value at index "+i); } buffer.unmap(clQueue, buf); + + //release + buffer.release(); + kernel.release(); + program.release(); } catch (AssertionError ex) { LOG.log(Level.SEVERE, "kernel test failed with an assertion error"); @@ -239,7 +250,8 @@ public class HelloOpenCL extends SimpleApplication { //copy to a buffer Buffer buffer = clContext.createBuffer(4*4*500*1024); - image.copyToBufferAsync(clQueue, buffer, new long[]{10,10,0}, new long[]{500,1024,1}, 0); + Event e3 = image.copyToBufferAsync(clQueue, buffer, new long[]{10,10,0}, new long[]{500,1024,1}, 0); + e3.release(); //this buffer must be completely red ByteBuffer map1 = buffer.map(clQueue, MappingAccess.MAP_READ_ONLY); FloatBuffer map1F = map1.asFloatBuffer(); map1F.rewind(); @@ -282,6 +294,11 @@ public class HelloOpenCL extends SimpleApplication { } image2.unmap(clQueue, map2); + //release + image.release(); + image2.release(); + buffer.release(); + } catch (AssertionError ex) { LOG.log(Level.SEVERE, "image test failed with an assertion error"); return false; diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java index 06e2684dc..0d2257817 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java @@ -107,6 +107,7 @@ public class TestVertexBufferSharing extends SimpleApplication { private void initOpenCL1() { clContext = context.getOpenCLContext(); clQueue = clContext.createQueue(); + clQueue.register(); //create kernel String source = "" + "__kernel void ScaleKernel(__global float* vb, float scale)\n" @@ -118,12 +119,15 @@ public class TestVertexBufferSharing extends SimpleApplication { + "}\n"; Program program = clContext.createProgramFromSourceCode(source); program.build(); + program.register(); kernel = program.createKernel("ScaleKernel"); + kernel.register(); } private void initOpenCL2() { //bind vertex buffer to OpenCL VertexBuffer vb = geom.getMesh().getBuffer(VertexBuffer.Type.Position); buffer = clContext.bindVertexBuffer(vb, MemoryAccess.READ_WRITE); + buffer.register(); ws = new com.jme3.opencl.Kernel.WorkSize(geom.getMesh().getVertexCount()); } private void updateOpenCL(float tpf) { @@ -131,15 +135,15 @@ public class TestVertexBufferSharing extends SimpleApplication { time += tpf; //aquire resource - buffer.acquireBufferForSharingAsync(clQueue); + buffer.acquireBufferForSharingAsync(clQueue).release(); //no need to wait for the returned event, since the kernel implicitely waits for it (same command queue) //execute kernel float scale = (float) Math.pow(1.1, (1.0 - time%2) / 16.0); - kernel.Run1(clQueue, ws, buffer, scale); + kernel.Run1(clQueue, ws, buffer, scale).release(); //release resource - buffer.releaseBufferForSharingAsync(clQueue); + buffer.releaseBufferForSharingAsync(clQueue).release(); } } \ No newline at end of file diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java index 5230fb69d..c1f3e612f 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java @@ -120,26 +120,31 @@ public class TestWriteToTexture extends SimpleApplication implements AnalogListe private void initOpenCL1() { clContext = context.getOpenCLContext(); clQueue = clContext.createQueue(); + clQueue.register(); //create kernel Program program = clContext.createProgramFromSourceFiles(assetManager, "jme3test/opencl/JuliaSet.cl"); program.build(); + program.register(); kernel = program.createKernel("JuliaSet"); + kernel.register(); C = new Vector2f(0.12f, -0.2f); } private void initOpenCL2() { //bind image to OpenCL texCL = clContext.bindImage(tex, MemoryAccess.WRITE_ONLY); + texCL.register(); } private void updateOpenCL(float tpf) { //aquire resource - texCL.acquireImageForSharingAsync(clQueue); + texCL.acquireImageForSharingAsync(clQueue).release(); //no need to wait for the returned event, since the kernel implicitely waits for it (same command queue) //execute kernel - kernel.Run1(clQueue, new com.jme3.opencl.Kernel.WorkSize(settings.getWidth(), settings.getHeight()), texCL, C, 16); + kernel.Run1(clQueue, new com.jme3.opencl.Kernel.WorkSize(settings.getWidth(), settings.getHeight()), texCL, C, 16) + .release(); //release resource - texCL.releaseImageForSharingAsync(clQueue); + texCL.releaseImageForSharingAsync(clQueue).release(); } @Override diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java index 773b581b1..06d417827 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java @@ -48,9 +48,9 @@ public class JoclBuffer extends Buffer { final CL cl; public JoclBuffer(long id) { + super(new ReleaserImpl(id)); this.id = id; this.cl = CLPlatform.getLowLevelCLInterface(); - OpenCLObjectManager.getInstance().registerObject(this); } @Override @@ -203,10 +203,6 @@ public class JoclBuffer extends Buffer { return new JoclEvent(event); } - @Override - public ObjectReleaser getReleaser() { - return new ReleaserImpl(id); - } private static class ReleaserImpl implements ObjectReleaser { private long mem; private ReleaserImpl(long mem) { diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclCommandQueue.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclCommandQueue.java index 790bc152b..e7b8a3743 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclCommandQueue.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclCommandQueue.java @@ -42,15 +42,15 @@ import com.jogamp.opencl.llb.CLCommandQueueBinding; * * @author shaman */ -public class JoclCommandQueue implements CommandQueue { +public class JoclCommandQueue extends CommandQueue { final CL cl; final long id; public JoclCommandQueue(long id) { + super(new ReleaserImpl(id)); this.id = id; this.cl = CLPlatform.getLowLevelCLInterface(); - OpenCLObjectManager.getInstance().registerObject(this); } @Override @@ -65,23 +65,17 @@ public class JoclCommandQueue implements CommandQueue { Utils.checkError(ret, "clFinish"); } - @Override - public ObjectReleaser getReleaser() { - return new ReleaserImpl(id, cl); - } private static class ReleaserImpl implements ObjectReleaser { private long id; - private CLCommandQueueBinding cl; - private ReleaserImpl(long id, CLCommandQueueBinding cl) { + private ReleaserImpl(long id) { this.id = id; - this.cl = cl; } @Override public void release() { if (id != 0) { - int ret = cl.clReleaseCommandQueue(id); + int ret = CLPlatform.getLowLevelCLInterface().clReleaseCommandQueue(id); id = 0; Utils.reportError(ret, "clReleaseCommandQueue"); } diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java index 4e9b6e920..eca2db012 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java @@ -40,7 +40,6 @@ import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture; import com.jogamp.opencl.CLContext; import com.jogamp.opencl.CLImageFormat; -import com.jogamp.opencl.CLMemory; import com.jogamp.opencl.CLMemory.Mem; import com.jogamp.opencl.CLPlatform; import com.jogamp.opencl.llb.CL; @@ -48,7 +47,6 @@ import com.jogamp.opencl.llb.gl.CLGL; import com.jogamp.opencl.llb.impl.CLImageFormatImpl; import com.jogamp.opengl.GL; import java.nio.ByteBuffer; -import java.nio.IntBuffer; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -66,11 +64,11 @@ public class JoclContext extends Context { private final List devices; public JoclContext(CLContext context, List devices) { + super(new ReleaserImpl(context.ID, devices)); this.context = context; this.id = context.ID; this.cl = context.getCL(); this.devices = devices; - OpenCLObjectManager.getInstance().registerObject(this); } public CLContext getContext() { @@ -224,10 +222,6 @@ public class JoclContext extends Context { return new JoclProgram(p, this); } - @Override - public ObjectReleaser getReleaser() { - return new ReleaserImpl(id, devices); - } private static class ReleaserImpl implements ObjectReleaser { private long id; private final List devices; diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclEvent.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclEvent.java index cb6fa9235..c79504dfa 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclEvent.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclEvent.java @@ -41,16 +41,16 @@ import java.util.logging.Logger; * * @author shaman */ -public class JoclEvent implements Event { +public class JoclEvent extends Event { private static final Logger LOG = Logger.getLogger(JoclEvent.class.getName()); final long id; final CL cl; public JoclEvent(long id) { + super(new ReleaserImpl(id)); this.id = id; this.cl = CLPlatform.getLowLevelCLInterface(); - OpenCLObjectManager.getInstance().registerObject(this); } @Override @@ -59,6 +59,7 @@ public class JoclEvent implements Event { Utils.pointers[0].put(0, id); int ret = cl.clWaitForEvents(1, Utils.pointers[0]); Utils.checkError(ret, "clWaitForEvents"); + release(); } @Override @@ -68,6 +69,7 @@ public class JoclEvent implements Event { Utils.checkError(err, "clGetEventInfo"); int status = Utils.tempBuffers[0].b16i.get(0); if (status == CL.CL_SUCCESS) { + release(); return true; } else if (status < 0) { Utils.checkError(status, "EventStatus"); @@ -76,11 +78,6 @@ public class JoclEvent implements Event { return false; } } - - @Override - public ObjectReleaser getReleaser() { - return new ReleaserImpl(id); - } private static class ReleaserImpl implements ObjectReleaser { private long event; diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java index aa6ce5ae7..0041147f9 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java @@ -44,16 +44,16 @@ import java.util.logging.Logger; * * @author shaman */ -public class JoclImage implements Image { +public class JoclImage extends Image { private static final Logger LOG = Logger.getLogger(JoclImage.class.getName()); final long id; final CL cl; public JoclImage(long image) { + super(new ReleaserImpl(image)); this.id = image; this.cl = CLPlatform.getLowLevelCLInterface(); - OpenCLObjectManager.getInstance().registerObject(this); } public static int decodeImageChannelOrder(ImageChannelOrder order) { @@ -512,10 +512,6 @@ public class JoclImage implements Image { return new JoclEvent(event); } - @Override - public ObjectReleaser getReleaser() { - return new ReleaserImpl(id); - } private static class ReleaserImpl implements ObjectReleaser { private long mem; private ReleaserImpl(long mem) { diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java index b7d99c5bc..43bac1a30 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java @@ -37,7 +37,6 @@ import com.jme3.math.Vector4f; import com.jme3.opencl.*; import com.jme3.opencl.Buffer; import com.jogamp.common.nio.PointerBuffer; -import com.jogamp.opencl.CLKernel; import com.jogamp.opencl.CLPlatform; import com.jogamp.opencl.llb.CL; import java.nio.*; @@ -55,6 +54,7 @@ public class JoclKernel extends Kernel { final CL cl; public JoclKernel(long kernel) { + super(new ReleaserImpl(kernel)); this.kernel = kernel; this.cl = CLPlatform.getLowLevelCLInterface(); OpenCLObjectManager.getInstance().registerObject(this); @@ -240,10 +240,6 @@ public class JoclKernel extends Kernel { return new JoclEvent(Utils.pointers[0].get(0)); } - @Override - public ObjectReleaser getReleaser() { - return new ReleaserImpl(kernel); - } private static class ReleaserImpl implements ObjectReleaser { private long kernel; private ReleaserImpl(long kernel) { diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java index dcc32014a..1714446cf 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java @@ -50,7 +50,7 @@ import static com.jogamp.opencl.llb.CL.CL_SUCCESS; * * @author shaman */ -public class JoclProgram implements Program { +public class JoclProgram extends Program { private static final Logger LOG = Logger.getLogger(JoclProgram.class.getName()); final long program; @@ -58,10 +58,10 @@ public class JoclProgram implements Program { private final JoclContext context; public JoclProgram(long program, JoclContext context) { + super(new ReleaserImpl(program)); this.program = program; this.context = context; this.cl = CLPlatform.getLowLevelCLInterface(); - OpenCLObjectManager.getInstance().registerObject(this); } @Override @@ -79,11 +79,6 @@ public class JoclProgram implements Program { LOG.log(Level.INFO, "Program compiled:\n{0}", Log()); } } - - @Override - public void build() throws KernelCompilationException { - build(""); - } private String Log(long device) { Utils.pointers[0].rewind(); @@ -131,10 +126,6 @@ public class JoclProgram implements Program { return kx; } - @Override - public ObjectReleaser getReleaser() { - return new ReleaserImpl(program); - } private static class ReleaserImpl implements ObjectReleaser { private long program; private ReleaserImpl(long program) { diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java index 60277427a..9a90c6eb1 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java @@ -44,8 +44,8 @@ public class LwjglBuffer extends Buffer { private final CLMem buffer; public LwjglBuffer(CLMem buffer) { + super(new ReleaserImpl(buffer)); this.buffer = buffer; - OpenCLObjectManager.getInstance().registerObject(this); } public CLMem getBuffer() { return buffer; @@ -205,10 +205,6 @@ public class LwjglBuffer extends Buffer { return new LwjglEvent(q.getCLEvent(event)); } - @Override - public ObjectReleaser getReleaser() { - return new ReleaserImpl(buffer); - } private static class ReleaserImpl implements ObjectReleaser { private CLMem mem; private ReleaserImpl(CLMem mem) { diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java index a0fd04ddc..c413d6a8e 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java @@ -40,13 +40,13 @@ import org.lwjgl.opencl.CLCommandQueue; * * @author shaman */ -public class LwjglCommandQueue implements CommandQueue { +public class LwjglCommandQueue extends CommandQueue { private final CLCommandQueue queue; public LwjglCommandQueue(CLCommandQueue queue) { + super(new ReleaserImpl(queue)); this.queue = queue; - OpenCLObjectManager.getInstance().registerObject(this); } public CLCommandQueue getQueue() { @@ -65,10 +65,6 @@ public class LwjglCommandQueue implements CommandQueue { Utils.checkError(ret, "clFinish"); } - @Override - public ObjectReleaser getReleaser() { - return new ReleaserImpl(queue); - } private static class ReleaserImpl implements ObjectReleaser { private CLCommandQueue queue; private ReleaserImpl(CLCommandQueue queue) { diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java index ad3450f8f..af5463f33 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java @@ -57,9 +57,9 @@ public class LwjglContext extends Context { private final List devices; public LwjglContext(CLContext context, List devices) { + super(new ReleaserImpl(context, devices)); this.context = context; this.devices = devices; - OpenCLObjectManager.getInstance().registerObject(this); } public CLContext getContext() { @@ -208,10 +208,6 @@ public class LwjglContext extends Context { return new LwjglProgram(p, this); } - @Override - public ObjectReleaser getReleaser() { - return new ReleaserImpl(context, devices); - } private static class ReleaserImpl implements ObjectReleaser { private CLContext context; private final List devices; diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java index 5055ac7af..1078c8c17 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java @@ -41,31 +41,24 @@ import org.lwjgl.opencl.CLEvent; * * @author shaman */ -public class LwjglEvent implements Event { +public class LwjglEvent extends Event { private static final Logger LOG = Logger.getLogger(LwjglEvent.class.getName()); private CLEvent event; + private ReleaserImpl releaser; public LwjglEvent(CLEvent event) { + super(new ReleaserImpl(event)); this.event = event; if (event == null) { LOG.warning("event is null!"); } else { - OpenCLObjectManager.getInstance().registerObject(this); + this.releaser = new ReleaserImpl(event); } } public CLEvent getEvent() { return event; } - - protected void release() { - if (event != null && event.isValid()) { - int ret = CL10.clReleaseEvent(event); - event = null; - Utils.reportError(ret, "clReleaseEvent"); - LOG.finer("Event deleted"); - } - } @Override public void waitForFinished() { @@ -93,11 +86,6 @@ public class LwjglEvent implements Event { } } - @Override - public ObjectReleaser getReleaser() { - return new ReleaserImpl(event); - } - private static class ReleaserImpl implements ObjectReleaser { private CLEvent event; diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java index 1ed59641b..46b8b0ff7 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java @@ -43,14 +43,14 @@ import org.lwjgl.opencl.api.CLImageFormat; * * @author shaman */ -public class LwjglImage implements Image { +public class LwjglImage extends Image { private static final Logger LOG = Logger.getLogger(LwjglImage.class.getName()); private final CLMem image; public LwjglImage(CLMem image) { + super(new ReleaserImpl(image)); this.image = image; - OpenCLObjectManager.getInstance().registerObject(this); } public CLMem getImage() { @@ -543,10 +543,6 @@ public class LwjglImage implements Image { return new LwjglEvent(q.getCLEvent(event)); } - @Override - public ObjectReleaser getReleaser() { - return new ReleaserImpl(image); - } private static class ReleaserImpl implements ObjectReleaser { private CLMem mem; private ReleaserImpl(CLMem mem) { diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java index 21f165df6..1897e2501 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java @@ -52,8 +52,8 @@ public class LwjglKernel extends Kernel { private final CLKernel kernel; public LwjglKernel(CLKernel kernel) { + super(new ReleaserImpl(kernel)); this.kernel = kernel; - OpenCLObjectManager.getInstance().registerObject(this); } public CLKernel getKernel() { diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java index a926c3d14..641951235 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java @@ -44,16 +44,16 @@ import org.lwjgl.opencl.*; * * @author shaman */ -public class LwjglProgram implements Program { +public class LwjglProgram extends Program { private static final Logger LOG = Logger.getLogger(LwjglProgram.class.getName()); private final CLProgram program; private final LwjglContext context; public LwjglProgram(CLProgram program, LwjglContext context) { + super(new ReleaserImpl(program)); this.program = program; this.context = context; - OpenCLObjectManager.getInstance().registerObject(this); } public CLProgram getProgram() { @@ -75,11 +75,6 @@ public class LwjglProgram implements Program { LOG.log(Level.INFO, "Program compiled:\n{0}", Log()); } } - - @Override - public void build() throws KernelCompilationException { - build(""); - } private String Log() { StringBuilder str = new StringBuilder(); @@ -109,10 +104,6 @@ public class LwjglProgram implements Program { return kx; } - @Override - public ObjectReleaser getReleaser() { - return new ReleaserImpl(program); - } private static class ReleaserImpl implements ObjectReleaser { private CLProgram program; private ReleaserImpl(CLProgram program) { From 54113f35e048dc27653ca9a1c84fea1ac48ee069 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Mon, 2 May 2016 14:21:02 +0200 Subject: [PATCH 23/40] added alternative versions for kernel launches and resource acquiring that do not return an event. This improves the performance. --- .../src/main/java/com/jme3/opencl/Buffer.java | 38 +++++++++++- .../src/main/java/com/jme3/opencl/Image.java | 38 ++++++++++++ .../src/main/java/com/jme3/opencl/Kernel.java | 62 ++++++++++++++++++- .../java/com/jme3/opencl/package-info.java | 14 +++++ .../opencl/TestVertexBufferSharing.java | 6 +- .../jme3test/opencl/TestWriteToTexture.java | 8 +-- .../java/com/jme3/opencl/jocl/JoclBuffer.java | 14 +++++ .../java/com/jme3/opencl/jocl/JoclImage.java | 14 +++++ .../java/com/jme3/opencl/jocl/JoclKernel.java | 18 ++++++ .../com/jme3/opencl/lwjgl/LwjglBuffer.java | 12 ++++ .../com/jme3/opencl/lwjgl/LwjglImage.java | 13 ++++ .../com/jme3/opencl/lwjgl/LwjglKernel.java | 17 +++++ 12 files changed, 244 insertions(+), 10 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java index 66ce0c8f7..ebb7d2bb2 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Buffer.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Buffer.java @@ -377,6 +377,29 @@ public abstract class Buffer extends AbstractOpenCLObject { * @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 @@ -387,5 +410,18 @@ public abstract class Buffer extends AbstractOpenCLObject { */ public abstract Event releaseBufferForSharingAsync(CommandQueue queue); - //TODO: add variants of the above two methods that don't create the event object, but release the event immediately + /** + * 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(); + } + } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Image.java b/jme3-core/src/main/java/com/jme3/opencl/Image.java index e58c20f7e..f9d9d9f28 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Image.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Image.java @@ -485,6 +485,30 @@ memory layout in which channels are stored in the image. * @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 @@ -495,5 +519,19 @@ memory layout in which channels are stored in the image. */ 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 } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java index 82fbf9018..17525a4bd 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java @@ -299,6 +299,9 @@ public abstract class Kernel extends AbstractOpenCLObject { /** * 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) @@ -306,6 +309,22 @@ public abstract class Kernel extends AbstractOpenCLObject { * @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. @@ -325,6 +344,28 @@ public abstract class Kernel extends AbstractOpenCLObject { 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. @@ -342,8 +383,25 @@ public abstract class Kernel extends AbstractOpenCLObject { return Run(queue); } - //TODO: add variants of the above three methods that don't create the event object, but release the event immediately - + /** + * 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 diff --git a/jme3-core/src/main/java/com/jme3/opencl/package-info.java b/jme3-core/src/main/java/com/jme3/opencl/package-info.java index 5b4fcbc0b..c96a026d1 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/package-info.java +++ b/jme3-core/src/main/java/com/jme3/opencl/package-info.java @@ -89,6 +89,16 @@ * 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. + *
    + * 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. * *

    * Interoperability between OpenCL and jME3:
    @@ -142,6 +152,10 @@ * 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. + *

  • {@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. * */ package com.jme3.opencl; diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java index 0d2257817..78e8e5de1 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java @@ -135,15 +135,15 @@ public class TestVertexBufferSharing extends SimpleApplication { time += tpf; //aquire resource - buffer.acquireBufferForSharingAsync(clQueue).release(); + 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.Run1(clQueue, ws, buffer, scale).release(); + kernel.Run1NoEvent(clQueue, ws, buffer, scale); //release resource - buffer.releaseBufferForSharingAsync(clQueue).release(); + buffer.releaseBufferForSharingNoEvent(clQueue); } } \ No newline at end of file diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java index c1f3e612f..5f3143832 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java @@ -136,15 +136,15 @@ public class TestWriteToTexture extends SimpleApplication implements AnalogListe } private void updateOpenCL(float tpf) { //aquire resource - texCL.acquireImageForSharingAsync(clQueue).release(); + texCL.acquireImageForSharingNoEvent(clQueue); //no need to wait for the returned event, since the kernel implicitely waits for it (same command queue) //execute kernel - kernel.Run1(clQueue, new com.jme3.opencl.Kernel.WorkSize(settings.getWidth(), settings.getHeight()), texCL, C, 16) - .release(); + Kernel.WorkSize ws = new Kernel.WorkSize(settings.getWidth(), settings.getHeight()); + kernel.Run1NoEvent(clQueue, ws, texCL, C, 16); //release resource - texCL.releaseImageForSharingAsync(clQueue).release(); + texCL.releaseImageForSharingNoEvent(clQueue); } @Override diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java index 06d417827..23cc4dda9 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java @@ -191,6 +191,13 @@ public class JoclBuffer extends Buffer { 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) { @@ -202,6 +209,13 @@ public class JoclBuffer extends Buffer { 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; diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java index 0041147f9..252debdf3 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java @@ -502,6 +502,13 @@ public class JoclImage extends Image { 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(); @@ -511,6 +518,13 @@ public class JoclImage extends Image { 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; diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java index 43bac1a30..708e226e2 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java @@ -239,6 +239,24 @@ public class JoclKernel extends Kernel { 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; diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java index 9a90c6eb1..bbf766df9 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java @@ -194,6 +194,12 @@ public class LwjglBuffer extends Buffer { 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) { @@ -204,6 +210,12 @@ public class LwjglBuffer extends Buffer { 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; diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java index 46b8b0ff7..b61629ed7 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java @@ -534,6 +534,13 @@ public class LwjglImage extends Image { 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(); @@ -542,6 +549,12 @@ public class LwjglImage extends Image { 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; diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java index 1897e2501..bc1edafd8 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java @@ -223,6 +223,23 @@ public class LwjglKernel extends Kernel { 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() { From 22307257e028536342df6644448e234a3f31d7a1 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Mon, 2 May 2016 20:57:28 +0200 Subject: [PATCH 24/40] added querying of the program binaries and building the programs from these binaries. TestVertexBufferSharing shows how this is used to build a simple program cache. --- .../main/java/com/jme3/opencl/Context.java | 18 ++++++ .../main/java/com/jme3/opencl/Program.java | 27 ++++++-- .../opencl/TestVertexBufferSharing.java | 61 +++++++++++++++---- .../com/jme3/opencl/lwjgl/LwjglContext.java | 11 ++++ .../com/jme3/opencl/lwjgl/LwjglProgram.java | 33 ++++++++-- 5 files changed, 128 insertions(+), 22 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index 10dde71fc..33d8a6843 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -367,4 +367,22 @@ public abstract class Context extends AbstractOpenCLObject { public Program createProgramFromSourceFiles(AssetManager assetManager, List 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...) }. + * Important: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); } diff --git a/jme3-core/src/main/java/com/jme3/opencl/Program.java b/jme3-core/src/main/java/com/jme3/opencl/Program.java index 3cfe7bf05..c3cbb89c0 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Program.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Program.java @@ -31,6 +31,8 @@ */ 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. @@ -49,21 +51,27 @@ public abstract class Program extends AbstractOpenCLObject { } /** - * Builds this program with the specified argument string. + * 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 + * 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) throws KernelCompilationException; + 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(""); + build("", null); } /** @@ -82,4 +90,15 @@ public abstract class Program extends AbstractOpenCLObject { */ 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); + } diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java index 78e8e5de1..295b7c354 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java @@ -40,11 +40,19 @@ 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 { @@ -106,19 +114,48 @@ public class TestVertexBufferSharing extends SimpleApplication { private void initOpenCL1() { clContext = context.getOpenCLContext(); - clQueue = clContext.createQueue(); + Device device = clContext.getDevices().get(0); + clQueue = clContext.createQueue(device); clQueue.register(); //create kernel - 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 program = clContext.createProgramFromSourceCode(source); - program.build(); + 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 + ByteBuffer bb = program.getBinary(device); + byte[] bytes = new byte[bb.remaining()]; + bb.get(bytes); + try { + Files.write(binaryFile.toPath(), bytes); + } catch (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(); diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java index af5463f33..32751129f 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java @@ -208,6 +208,17 @@ public class LwjglContext extends Context { 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, "clCreateProgramWithSource"); + Utils.checkError(Utils.tempBuffers[0].b16i, "clCreateProgramWithSource"); + return new LwjglProgram(p, this); + } + private static class ReleaserImpl implements ObjectReleaser { private CLContext context; private final List devices; diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java index 641951235..f0a1b2df6 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java @@ -31,10 +31,8 @@ */ package com.jme3.opencl.lwjgl; -import com.jme3.opencl.Kernel; -import com.jme3.opencl.KernelCompilationException; -import com.jme3.opencl.OpenCLObjectManager; -import com.jme3.opencl.Program; +import com.jme3.opencl.*; +import java.nio.ByteBuffer; import java.util.logging.Level; import java.util.logging.Logger; import org.lwjgl.PointerBuffer; @@ -61,8 +59,17 @@ public class LwjglProgram extends Program { } @Override - public void build(String args) throws KernelCompilationException { - int ret = CL10.clBuildProgram(program, (PointerBuffer) null, args, null); + 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); @@ -104,6 +111,20 @@ public class LwjglProgram extends Program { 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 Date: Mon, 2 May 2016 20:58:39 +0200 Subject: [PATCH 25/40] Querying the program binaries won't be supported by the Jocl binding. See the comments inside JoclProgram.getBinary for the reason. --- .../com/jme3/opencl/jocl/JoclContext.java | 6 ++++ .../com/jme3/opencl/jocl/JoclProgram.java | 35 ++++++++++++++----- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java index eca2db012..163e27c68 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java @@ -222,6 +222,12 @@ public class JoclContext extends Context { return new JoclProgram(p, this); } + @Override + public Program createProgramFromBinary(ByteBuffer binaries, Device device) { + //Not supported because JoclProgram.getBinaries is also not supported. + throw new UnsupportedOperationException("No supported by Jocl"); + } + private static class ReleaserImpl implements ObjectReleaser { private long id; private final List devices; diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java index 1714446cf..157ce63cf 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java @@ -31,12 +31,10 @@ */ package com.jme3.opencl.jocl; -import com.jme3.opencl.Kernel; -import com.jme3.opencl.KernelCompilationException; -import com.jme3.opencl.OpenCLObjectManager; -import com.jme3.opencl.Program; +import com.jme3.opencl.*; 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; @@ -44,8 +42,6 @@ import java.util.logging.Level; import java.util.logging.Logger; import static com.jogamp.common.nio.Buffers.newDirectByteBuffer; -import static com.jogamp.opencl.CLException.newException; -import static com.jogamp.opencl.llb.CL.CL_SUCCESS; /** * * @author shaman @@ -65,8 +61,18 @@ public class JoclProgram extends Program { } @Override - public void build(String args) throws KernelCompilationException { - int ret = cl.clBuildProgram(program, 0, null, args, null); + 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); @@ -126,6 +132,19 @@ public class JoclProgram extends Program { return kx; } + @Override + public ByteBuffer getBinary(Device device) { + //There is no way to do this in Jocl: + //The low-level bindings need a buffer of adresses to buffers. For that + //the class InternalBufferUtil is used, but this class is not public. + //I also can't create a temporal instance of CLProgram because the constructor + //that takes only the native pointer is private. + //So the only way would be to create the CLProgram directly from the beginning. + //I don't want to do this because then I would have to use the whole + //bunch of garbage the CLProgram class is doing in background. + throw new UnsupportedOperationException("Jocl does not expose this operation"); + } + private static class ReleaserImpl implements ObjectReleaser { private long program; private ReleaserImpl(long program) { From a2df82b9e0d23b7aa31ddbded6fb1144b7334f36 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Mon, 2 May 2016 21:39:27 +0200 Subject: [PATCH 26/40] implemented a cache for program objects --- .../main/java/com/jme3/opencl/Program.java | 2 +- .../java/com/jme3/opencl/ProgramCache.java | 214 ++++++++++++++++++ .../jme3test/opencl/TestWriteToTexture.java | 14 +- 3 files changed, 227 insertions(+), 3 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/opencl/ProgramCache.java diff --git a/jme3-core/src/main/java/com/jme3/opencl/Program.java b/jme3-core/src/main/java/com/jme3/opencl/Program.java index c3cbb89c0..a98cf2c02 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Program.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Program.java @@ -71,7 +71,7 @@ public abstract class Program extends AbstractOpenCLObject { * @see #build(java.lang.String) */ public void build() throws KernelCompilationException { - build("", null); + build("", (Device[]) null); } /** diff --git a/jme3-core/src/main/java/com/jme3/opencl/ProgramCache.java b/jme3-core/src/main/java/com/jme3/opencl/ProgramCache.java new file mode 100644 index 000000000..0356cf3d7 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/opencl/ProgramCache.java @@ -0,0 +1,214 @@ +/* + * 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) }. + *
    + * The programs are identified by a unique id. The following format is recommended: + * {@code id = .}. + * + * @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 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}. + *

    + * 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 = .}. + *

    + * 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) }. + *
    + * The id must be unique, otherwise collisions within the cache occur. + * Therefore, the following naming schema is recommended: + * {@code id = .}. + * + * @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(); + } + } + } +} diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java index 5f3143832..bb407893c 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestWriteToTexture.java @@ -49,6 +49,8 @@ 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 { @@ -59,6 +61,7 @@ public class TestWriteToTexture extends SimpleApplication implements AnalogListe private int initCounter; private Context clContext; private CommandQueue clQueue; + private ProgramCache programCache; private Kernel kernel; private Vector2f C; private Image texCL; @@ -121,9 +124,16 @@ public class TestWriteToTexture extends SimpleApplication implements AnalogListe clContext = context.getOpenCLContext(); clQueue = clContext.createQueue(); clQueue.register(); + programCache = new ProgramCache(clContext); //create kernel - Program program = clContext.createProgramFromSourceFiles(assetManager, "jme3test/opencl/JuliaSet.cl"); - program.build(); + 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(); From e35bb7dcbc618b82c8ea3cdda816622cea91955b Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Thu, 5 May 2016 19:49:51 +0200 Subject: [PATCH 27/40] added a constructor that disables the program cache: used during development --- .../java/com/jme3/opencl/OpenCLObjectManager.java | 4 ++-- .../main/java/com/jme3/opencl/ProgramCache.java | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java index 1d29a829f..4b761da5b 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java +++ b/jme3-core/src/main/java/com/jme3/opencl/OpenCLObjectManager.java @@ -43,8 +43,8 @@ import java.util.logging.Logger; */ public class OpenCLObjectManager { private static final Logger LOG = Logger.getLogger(OpenCLObjectManager.class.getName()); - private static final Level LOG_LEVEL1 = Level.INFO; - private static final Level LOG_LEVEL2 = Level.INFO; + private static final Level LOG_LEVEL1 = Level.FINER; + private static final Level LOG_LEVEL2 = Level.FINE; /** * Call Runtime.getRuntime().gc() every these frames */ diff --git a/jme3-core/src/main/java/com/jme3/opencl/ProgramCache.java b/jme3-core/src/main/java/com/jme3/opencl/ProgramCache.java index 0356cf3d7..bc533acaf 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/ProgramCache.java +++ b/jme3-core/src/main/java/com/jme3/opencl/ProgramCache.java @@ -59,6 +59,21 @@ public class ProgramCache { 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.
    + * 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. From 5e098b049300c52d8e00a8f090d674319c07d736 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Sun, 8 May 2016 17:05:43 +0200 Subject: [PATCH 28/40] worked on LWJGL3 support --- .../com/jme3/system/android/OGLESContext.java | 6 + .../opencl/TestVertexBufferSharing.java | 8 +- .../com/jme3/system/ios/IGLESContext.java | 7 + .../com/jme3/opencl/lwjgl/LwjglEvent.java | 7 - .../com/jme3/opencl/lwjgl/LwjglBuffer.java | 235 +++++++ .../jme3/opencl/lwjgl/LwjglCommandQueue.java | 80 +++ .../com/jme3/opencl/lwjgl/LwjglContext.java | 252 ++++++++ .../com/jme3/opencl/lwjgl/LwjglDevice.java | 303 +++++++++ .../com/jme3/opencl/lwjgl/LwjglEvent.java | 94 +++ .../com/jme3/opencl/lwjgl/LwjglImage.java | 576 ++++++++++++++++++ .../com/jme3/opencl/lwjgl/LwjglKernel.java | 218 +++++++ .../com/jme3/opencl/lwjgl/LwjglPlatform.java | 128 ++++ .../com/jme3/opencl/lwjgl/LwjglProgram.java | 178 ++++++ .../java/com/jme3/opencl/lwjgl/Utils.java | 155 +++++ .../com/jme3/system/lwjgl/LwjglContext.java | 158 ++++- 15 files changed, 2385 insertions(+), 20 deletions(-) create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/Utils.java diff --git a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java index 991ad25c0..35c3c3911 100644 --- a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java +++ b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java @@ -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; + } } diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java index 295b7c354..514a41d63 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestVertexBufferSharing.java @@ -146,12 +146,12 @@ public class TestVertexBufferSharing extends SimpleApplication { program = clContext.createProgramFromSourceCode(source); program.build(); //Save binary - ByteBuffer bb = program.getBinary(device); - byte[] bytes = new byte[bb.remaining()]; - bb.get(bytes); try { + ByteBuffer bb = program.getBinary(device); + byte[] bytes = new byte[bb.remaining()]; + bb.get(bytes); Files.write(binaryFile.toPath(), bytes); - } catch (IOException ex) { + } catch (UnsupportedOperationException | OpenCLException | IOException ex) { LOG.log(Level.SEVERE, "Unable to save program binaries", ex); } LOG.info("create new program from sources"); diff --git a/jme3-ios/src/main/java/com/jme3/system/ios/IGLESContext.java b/jme3-ios/src/main/java/com/jme3/system/ios/IGLESContext.java index 2d046550e..14ab252a5 100644 --- a/jme3-ios/src/main/java/com/jme3/system/ios/IGLESContext.java +++ b/jme3-ios/src/main/java/com/jme3/system/ios/IGLESContext.java @@ -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; + } } \ No newline at end of file diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java index 1078c8c17..b7f992c95 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java @@ -32,7 +32,6 @@ package com.jme3.opencl.lwjgl; import com.jme3.opencl.Event; -import com.jme3.opencl.OpenCLObjectManager; import java.util.logging.Logger; import org.lwjgl.opencl.CL10; import org.lwjgl.opencl.CLEvent; @@ -44,16 +43,10 @@ import org.lwjgl.opencl.CLEvent; public class LwjglEvent extends Event { private static final Logger LOG = Logger.getLogger(LwjglEvent.class.getName()); private CLEvent event; - private ReleaserImpl releaser; public LwjglEvent(CLEvent event) { super(new ReleaserImpl(event)); this.event = event; - if (event == null) { - LOG.warning("event is null!"); - } else { - this.releaser = new ReleaserImpl(event); - } } public CLEvent getEvent() { diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java new file mode 100644 index 000000000..f91cf0692 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java @@ -0,0 +1,235 @@ +/* + * 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) { + 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.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) { + 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"); + } + } + + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java new file mode 100644 index 000000000..5be22813a --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglCommandQueue.java @@ -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"); + } + } + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java new file mode 100644 index 000000000..e8c2aca26 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java @@ -0,0 +1,252 @@ +/* + * 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 devices; + + public LwjglContext(long context, List devices) { + super(new ReleaserImpl(context, devices)); + this.context = context; + this.devices = devices; + } + + public long getContext() { + return context; + } + + @Override + public List 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 devices; + private ReleaserImpl(long mem, List 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"); + } + } + + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java new file mode 100644 index 000000000..31325a469 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglDevice.java @@ -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 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(); + } + +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java new file mode 100644 index 000000000..5ded851d3 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglEvent.java @@ -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"); + } + } + + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java new file mode 100644 index 000000000..ff9606c13 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java @@ -0,0 +1,576 @@ +/* + * 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) { + 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.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) { + 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"); + } + } + + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java new file mode 100644 index 000000000..9e4a31a73 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java @@ -0,0 +1,218 @@ +/* + * 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.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, 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"); + } + } + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java new file mode 100644 index 000000000..74fc685c1 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglPlatform.java @@ -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 devices; + + public LwjglPlatform(CLPlatform platform) { + this.platform = platform; + } + + public CLPlatform getPlatform() { + return platform; + } + + @Override + public List 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 getExtensions() { + return Arrays.asList(Info.clGetPlatformInfoStringASCII(platform.address(), CL10.CL_PLATFORM_EXTENSIONS).split(" ")); + } + +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java new file mode 100644 index 000000000..5e1e06466 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java @@ -0,0 +1,178 @@ +/* + * 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() { + 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)); + 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 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); + } + } + +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index 986544510..4b60bd0d2 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -36,6 +36,12 @@ 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; @@ -44,19 +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; @@ -81,8 +89,7 @@ public abstract class LwjglContext implements JmeContext { protected Timer timer; protected SystemListener listener; - protected long clPlatform; - protected Context clContext; + protected com.jme3.opencl.lwjgl.LwjglContext clContext; public void setSystemListener(SystemListener listener) { this.listener = listener; @@ -194,6 +201,139 @@ public abstract class LwjglContext implements JmeContext { protected void initOpenCL() { 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 platforms = new ArrayList<>(); + for (CLPlatform p : CLPlatform.getPlatforms()) { + platforms.add(new LwjglPlatform(p)); + } + platformInfos.append("Available OpenCL platforms:"); + for (int i=0; i devices = platform.getDevices(); + platformInfos.append("\n * Available devices:"); + for (int j=0; j choosenDevices = chooser.chooseDevices(platforms); + List 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); + clContext = new com.jme3.opencl.lwjgl.LwjglContext(c, (List) 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 devices) 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 + //TODO: test on Linus and MacOSX + switch ( org.lwjgl.system.Platform.get() ) { + case WINDOWS: + long wglContext = org.lwjgl.opengl.WGL.wglGetCurrentContext(); + long wglDC = org.lwjgl.opengl.WGL.wglGetCurrentDC(); + properties.put(KHRGLSharing.CL_GL_CONTEXT_KHR).put(wglContext); + properties.put(KHRGLSharing.CL_WGL_HDC_KHR).put(wglDC); + break; + case LINUX: + properties.put(KHRGLSharing.CL_GL_CONTEXT_KHR).put(org.lwjgl.opengl.GLX.glXGetCurrentContext()); + properties.put(KHRGLSharing.CL_GLX_DISPLAY_KHR).put(org.lwjgl.opengl.GLX.glXGetCurrentDrawable()); + break; + case MACOSX: + properties.put(APPLEGLSharing.CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE) + .put(org.lwjgl.opengl.CGL.CGLGetShareGroup(org.lwjgl.opengl.CGL.CGLGetCurrentContext())); + break; + default: + throw new UnsupportedOperationException("CL/GL context sharing is not supported on this platform."); + } + properties.put(CL_CONTEXT_PLATFORM).put(platform); + properties.put(0); + + 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() { From 9a3dce2fb3a81b01b7b3aee6d2f23b34a2c85bcc Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Mon, 9 May 2016 07:55:46 +0200 Subject: [PATCH 29/40] OpenGL/CL sharing is not working with lwjgl3. It seems that the context is set up the wrong way. For now, disable the sharing methods. Also retrieving the program binaries is disabled, the current implementation would throw a segfault. --- jme3-examples/build.gradle | 1 + .../src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java | 2 ++ .../main/java/com/jme3/opencl/lwjgl/LwjglContext.java | 3 +++ .../src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java | 2 ++ .../main/java/com/jme3/opencl/lwjgl/LwjglProgram.java | 2 +- .../src/main/java/com/jme3/opencl/lwjgl/Utils.java | 6 ++++++ .../main/java/com/jme3/system/lwjgl/LwjglContext.java | 9 +++++++++ 7 files changed, 24 insertions(+), 1 deletion(-) diff --git a/jme3-examples/build.gradle b/jme3-examples/build.gradle index be2e106a6..47ee94c72 100644 --- a/jme3-examples/build.gradle +++ b/jme3-examples/build.gradle @@ -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') diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java index f91cf0692..298a13059 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java @@ -203,6 +203,7 @@ public class LwjglBuffer extends Buffer { @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]); @@ -212,6 +213,7 @@ public class LwjglBuffer extends Buffer { } @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"); diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java index e8c2aca26..932c486a3 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglContext.java @@ -161,6 +161,7 @@ public class LwjglContext extends Context { @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"); @@ -174,6 +175,7 @@ public class LwjglContext extends Context { @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"); @@ -188,6 +190,7 @@ public class LwjglContext extends Context { @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"); diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java index ff9606c13..5b9c06e66 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java @@ -544,6 +544,7 @@ public class LwjglImage extends Image { } @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]); @@ -553,6 +554,7 @@ public class LwjglImage extends Image { } @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"); diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java index 5e1e06466..15f46fc9c 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java @@ -153,7 +153,7 @@ public class LwjglProgram extends Program { ByteBuffer binaries = ByteBuffer.allocateDirect(size); binaryPointers.put(index, binaries); - //TODO: why the hell does this throw a segfault ?!? + //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"); diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/Utils.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/Utils.java index d328a220a..c899dc2ff 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/Utils.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/Utils.java @@ -50,6 +50,12 @@ 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()); diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index 4b60bd0d2..cf32af063 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -75,6 +75,10 @@ public abstract class LwjglContext implements JmeContext { private static final Logger logger = Logger.getLogger(LwjglContext.class.getName()); + //Fixme: OpenGL/CL sharing does not work yet, this line disables the sharing methods + //(They will throw an OpenCLException) + public static final boolean CL_GL_SHARING_POSSIBLE = false; + protected static final String THREAD_NAME = "jME3 Main"; protected AtomicBoolean created = new AtomicBoolean(false); @@ -296,6 +300,11 @@ public abstract class LwjglContext implements JmeContext { logger.info("OpenCL context created"); } private long createContext(final CLPlatform platform, final List devices) throws Exception { + + //Fixme: OpenGL/CL sharing does not work. The properties seem to be setup wrongly + // If it works, set CL_GL_SHARING_POSSIBLE to true to enable the sharing + // methods again + final int propertyCount = 2 + 4 + 1; final PointerBuffer properties = PointerBuffer.allocateDirect(propertyCount + devices.size()); From 44899098e26534f8b8154f61d9b0469533148082 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Mon, 9 May 2016 17:43:49 +0200 Subject: [PATCH 30/40] added dependency resolving and a random number library --- .../main/java/com/jme3/opencl/Context.java | 65 ++++- .../main/resources/Common/OpenCL/Random.clh | 185 +++++++++++++ .../jme3test/opencl/TestOpenCLLibraries.java | 257 ++++++++++++++++++ 3 files changed, 500 insertions(+), 7 deletions(-) create mode 100644 jme3-core/src/main/resources/Common/OpenCL/Random.clh create mode 100644 jme3-examples/src/main/java/jme3test/opencl/TestOpenCLLibraries.java diff --git a/jme3-core/src/main/java/com/jme3/opencl/Context.java b/jme3-core/src/main/java/com/jme3/opencl/Context.java index 33d8a6843..fed3cd2a3 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Context.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Context.java @@ -34,6 +34,7 @@ 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; @@ -43,6 +44,7 @@ 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; @@ -282,6 +284,52 @@ public abstract class Context extends AbstractOpenCLObject { */ 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(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, @@ -294,14 +342,15 @@ public abstract class Context extends AbstractOpenCLObject { *

  • Some common OpenCL files used as libraries (Convention: file names end with {@code .clh}
  • *
  • One main OpenCL file containing the actual kernels (Convention: file name ends with {@code .cl})
  • * - * Note: Files that can't be loaded are skipped.
    * - * The actual creation is handled by {@link #createProgramFromSourceCode(java.lang.String) }. + * 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)); @@ -319,14 +368,15 @@ public abstract class Context extends AbstractOpenCLObject { *
  • Some common OpenCL files used as libraries (Convention: file names end with {@code .clh}
  • *
  • One main OpenCL file containing the actual kernels (Convention: file name ends with {@code .cl})
  • * - * Note: Files that can't be loaded are skipped.
    * - * The actual creation is handled by {@link #createProgramFromSourceCode(java.lang.String) }. + * 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 resources) { StringBuilder str = new StringBuilder(); @@ -334,8 +384,7 @@ public abstract class Context extends AbstractOpenCLObject { for (String res : resources) { AssetInfo info = assetManager.locateAsset(new AssetKey(res)); if (info == null) { - LOG.log(Level.WARNING, "unable to load source file ''{0}''", res); - continue; + throw new AssetNotFoundException("Unable to load source file \""+res+"\""); } try (BufferedReader reader = new BufferedReader(new InputStreamReader(info.openStream()))) { while (true) { @@ -349,12 +398,13 @@ public abstract class Context extends AbstractOpenCLObject { LOG.log(Level.WARNING, "unable to load source file '"+res+"'", ex); } } - return createProgramFromSourceCode(str.toString()); + 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); @@ -363,6 +413,7 @@ public abstract class Context extends AbstractOpenCLObject { /** * 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 resources) { return createProgramFromSourceFilesWithInclude(assetManager, "", resources); diff --git a/jme3-core/src/main/resources/Common/OpenCL/Random.clh b/jme3-core/src/main/resources/Common/OpenCL/Random.clh new file mode 100644 index 000000000..18127e153 --- /dev/null +++ b/jme3-core/src/main/resources/Common/OpenCL/Random.clh @@ -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: + * + * __kernel void TestRandom(__global ulong* seeds) { + * // ... + * int i = randInt(seeds + get_global_id(0)); + * // --- + * } + * + */ +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: + * + * __kernel void TestRandom(__global ulong* seeds) { + * // ... + * int i = randIntN(n, seeds + get_global_id(0)); + * // --- + * } + * + */ +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: + * + * __kernel void TestRandom(__global ulong* seeds) { + * // ... + * long l = randLong(seeds + get_global_id(0)); + * // --- + * } + * + */ +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: + * + * __kernel void TestRandom(__global ulong* seeds) { + * // ... + * bool b = randBool(seeds + get_global_id(0)); + * // --- + * } + * + */ +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: + * + * __kernel void TestRandom(__global ulong* seeds) { + * // ... + * double d = randDouble(seeds + get_global_id(0)); + * // --- + * } + * + */ +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: + * + * __kernel void TestRandom(__global ulong* seeds) { + * // ... + * float f = randFloat(seeds + get_global_id(0)); + * // --- + * } + * + */ +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: + * + * __kernel void TestRandom(__global ulong* seeds) { + * // ... + * float2 f2 = randGausianf(seeds + get_global_id(0)); + * // --- + * } + * + */ +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: + * + * __kernel void TestRandom(__global ulong* seeds) { + * // ... + * double2 f2 = randGausian(seeds + get_global_id(0)); + * // --- + * } + * + */ +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 \ No newline at end of file diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestOpenCLLibraries.java b/jme3-examples/src/main/java/jme3test/opencl/TestOpenCLLibraries.java new file mode 100644 index 000000000..9f27203cf --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/opencl/TestOpenCLLibraries.java @@ -0,0 +1,257 @@ +/* + * 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.*; +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)); + + 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 Date: Tue, 10 May 2016 07:26:22 +0200 Subject: [PATCH 31/40] added matrix support for kernel arguments (mapped to float16) --- .../src/main/java/com/jme3/opencl/Kernel.java | 31 ++++++++++++++++--- .../java/com/jme3/opencl/jocl/JoclKernel.java | 14 +++++++++ .../main/java/com/jme3/opencl/jocl/Utils.java | 2 ++ .../com/jme3/opencl/lwjgl/LwjglKernel.java | 14 +++++++++ .../java/com/jme3/opencl/lwjgl/Utils.java | 4 ++- .../com/jme3/opencl/lwjgl/LwjglKernel.java | 14 +++++++++ .../java/com/jme3/opencl/lwjgl/Utils.java | 2 ++ 7 files changed, 76 insertions(+), 5 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java index 17525a4bd..09f22a813 100644 --- a/jme3-core/src/main/java/com/jme3/opencl/Kernel.java +++ b/jme3-core/src/main/java/com/jme3/opencl/Kernel.java @@ -31,9 +31,8 @@ */ package com.jme3.opencl; -import com.jme3.math.Quaternion; -import com.jme3.math.Vector2f; -import com.jme3.math.Vector4f; +import com.jme3.math.*; +import com.jme3.util.TempVars; import java.nio.ByteBuffer; import java.util.Arrays; @@ -237,6 +236,24 @@ public abstract class Kernel extends AbstractOpenCLObject { 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 @@ -253,7 +270,9 @@ public abstract class Kernel extends AbstractOpenCLObject { * Sets the kernel argument at the specified index.
    * The argument must be a known type: * {@code LocalMemPerElement, LocalMem, Image, Buffer, byte, short, int, - * long, float, double, Vector2f, Vector4f, Quaternion} + * long, float, double, Vector2f, Vector4f, Quaternion, Matrix3f, Matrix4f}. + *
    + * 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 @@ -277,6 +296,10 @@ public abstract class Kernel extends AbstractOpenCLObject { 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) { diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java index 708e226e2..3d3705c76 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclKernel.java @@ -31,6 +31,7 @@ */ 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; @@ -213,6 +214,19 @@ public class JoclKernel extends Kernel { 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); + int ret = cl.clSetKernelArg(kernel, index, 16*4, buf); + Utils.checkError(ret, "clSetKernelArg"); + } @Override public void setArg(int index, ByteBuffer buffer, long size) { diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/Utils.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/Utils.java index 6b2791d7a..c1b8c91d7 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/Utils.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/Utils.java @@ -86,6 +86,7 @@ public class Utils { } 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 { @@ -96,6 +97,7 @@ public class Utils { errorBuffer = BufferUtils.createIntBuffer(1); b80 = BufferUtils.createByteBuffer(80); b80l = b80.asLongBuffer(); + b80f = b80.asFloatBuffer(); } public static IntBuffer errorBuffer; diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java index bc1edafd8..b635e6705 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java @@ -31,6 +31,7 @@ */ 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; @@ -196,6 +197,19 @@ public class LwjglKernel extends Kernel { 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); + int ret = CL10.clSetKernelArg(kernel, index, buf); + Utils.checkError(ret, "clSetKernelArg"); + } @Override public void setArg(int index, ByteBuffer buffer, long size) { diff --git a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java index 082acb3d2..29b141325 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java +++ b/jme3-lwjgl/src/main/java/com/jme3/opencl/lwjgl/Utils.java @@ -89,8 +89,9 @@ public class Utils { b16d = b16.asDoubleBuffer(); } } - public static final ByteBuffer b80; //needed for ImageDescriptor + 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 { @@ -101,6 +102,7 @@ public class Utils { errorBuffer = BufferUtils.createIntBuffer(1); b80 = BufferUtils.createByteBuffer(80); b80l = b80.asLongBuffer(); + b80f = b80.asFloatBuffer(); } public static IntBuffer errorBuffer; diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java index 9e4a31a73..28c65d3a0 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java @@ -31,6 +31,7 @@ */ 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; @@ -152,6 +153,19 @@ public class LwjglKernel extends Kernel { 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); + int ret = CL10.clSetKernelArg(kernel, index, buf); + Utils.checkError(ret, "clSetKernelArg"); + } @Override public void setArg(int index, ByteBuffer buffer, long size) { diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/Utils.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/Utils.java index c899dc2ff..f896954ae 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/Utils.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/Utils.java @@ -87,6 +87,7 @@ public class Utils { } 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 { @@ -97,6 +98,7 @@ public class Utils { errorBuffer = BufferUtils.createIntBuffer(1); b80 = BufferUtils.createByteBuffer(80); b80l = b80.asLongBuffer(); + b80f = b80.asFloatBuffer(); } public static IntBuffer errorBuffer; From 4e55e0e5a0f459a78a83905d269f527b57294775 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Tue, 10 May 2016 14:55:42 +0200 Subject: [PATCH 32/40] added library for Matrix3f, fixed some bugs --- .../main/resources/Common/OpenCL/Matrix3f.clh | 224 ++++++++++++++++++ .../main/resources/Common/OpenCL/Matrix4f.clh | 12 + .../jme3test/opencl/TestOpenCLLibraries.java | 62 +++++ .../java/com/jme3/opencl/jocl/JoclKernel.java | 1 + .../com/jme3/opencl/lwjgl/LwjglBuffer.java | 1 + .../com/jme3/opencl/lwjgl/LwjglImage.java | 1 + .../com/jme3/opencl/lwjgl/LwjglKernel.java | 1 + .../com/jme3/opencl/lwjgl/LwjglKernel.java | 1 + 8 files changed, 303 insertions(+) create mode 100644 jme3-core/src/main/resources/Common/OpenCL/Matrix3f.clh create mode 100644 jme3-core/src/main/resources/Common/OpenCL/Matrix4f.clh diff --git a/jme3-core/src/main/resources/Common/OpenCL/Matrix3f.clh b/jme3-core/src/main/resources/Common/OpenCL/Matrix3f.clh new file mode 100644 index 000000000..3888a8e74 --- /dev/null +++ b/jme3-core/src/main/resources/Common/OpenCL/Matrix3f.clh @@ -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) Date: Wed, 11 May 2016 09:02:50 +0200 Subject: [PATCH 33/40] Added a library for Matrix4f --- .../main/resources/Common/OpenCL/Matrix4f.clh | 307 ++++++++++++++++++ .../jme3test/opencl/TestOpenCLLibraries.java | 86 ++++- 2 files changed, 392 insertions(+), 1 deletion(-) diff --git a/jme3-core/src/main/resources/Common/OpenCL/Matrix4f.clh b/jme3-core/src/main/resources/Common/OpenCL/Matrix4f.clh index b2af2b127..0df3de3d1 100644 --- a/jme3-core/src/main/resources/Common/OpenCL/Matrix4f.clh +++ b/jme3-core/src/main/resources/Common/OpenCL/Matrix4f.clh @@ -9,4 +9,311 @@ 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 \ No newline at end of file diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestOpenCLLibraries.java b/jme3-examples/src/main/java/jme3test/opencl/TestOpenCLLibraries.java index a291ad3b2..766437c65 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestOpenCLLibraries.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestOpenCLLibraries.java @@ -36,7 +36,9 @@ 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; @@ -84,6 +86,7 @@ public class TestOpenCLLibraries extends SimpleApplication { 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(); @@ -279,7 +282,7 @@ public class TestOpenCLLibraries extends SimpleApplication { + "}\n"; Program program = clContext.createProgramFromSourceCodeWithDependencies(code, assetManager); program.build(); - com.jme3.opencl.Buffer buffer = clContext.createBuffer(4 * 1); + com.jme3.opencl.Buffer buffer = clContext.createBuffer(1); Kernel testMatrix3fKernel1 = program.createKernel("TestMatrix3f_1"); testMatrix3fKernel1.Run1NoEvent(clQueue, new Kernel.WorkSize(1), buffer); @@ -316,4 +319,85 @@ public class TestOpenCLLibraries extends SimpleApplication { 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, "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; + } } \ No newline at end of file From 732e75fba6269e715f4018f8b98bdba17999c2d5 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Wed, 11 May 2016 09:19:30 +0200 Subject: [PATCH 34/40] fixed unmapping of buffer objects and an error in setArg in Lwjgl3's Kernel --- .../src/main/resources/Common/OpenCL/Random.clh | 12 ++++++------ .../java/jme3test/opencl/TestOpenCLLibraries.java | 12 ++++++------ .../main/java/com/jme3/opencl/jocl/JoclBuffer.java | 1 + .../main/java/com/jme3/opencl/jocl/JoclImage.java | 1 + .../main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java | 1 + .../main/java/com/jme3/opencl/lwjgl/LwjglImage.java | 1 + .../main/java/com/jme3/opencl/lwjgl/LwjglKernel.java | 2 +- 7 files changed, 17 insertions(+), 13 deletions(-) diff --git a/jme3-core/src/main/resources/Common/OpenCL/Random.clh b/jme3-core/src/main/resources/Common/OpenCL/Random.clh index 18127e153..9891441c8 100644 --- a/jme3-core/src/main/resources/Common/OpenCL/Random.clh +++ b/jme3-core/src/main/resources/Common/OpenCL/Random.clh @@ -5,13 +5,13 @@ //#define RANDOM_DOUBLES #ifdef RANDOM_DOUBLES -#ifdef cl_khr_fp64 +//#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 +//#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) diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestOpenCLLibraries.java b/jme3-examples/src/main/java/jme3test/opencl/TestOpenCLLibraries.java index 766437c65..396411397 100644 --- a/jme3-examples/src/main/java/jme3test/opencl/TestOpenCLLibraries.java +++ b/jme3-examples/src/main/java/jme3test/opencl/TestOpenCLLibraries.java @@ -250,10 +250,10 @@ public class TestOpenCLLibraries extends SimpleApplication { program.release(); } catch (AssertionError ex) { - LOG.log(Level.SEVERE, "kernel test failed with an assertion error"); + LOG.log(Level.SEVERE, "random test failed with an assertion error"); return false; } catch (Exception ex) { - LOG.log(Level.SEVERE, "kernel test failed with:", ex); + LOG.log(Level.SEVERE, "random test failed with:", ex); return false; } return true; @@ -310,10 +310,10 @@ public class TestOpenCLLibraries extends SimpleApplication { buffer.release(); } catch (AssertionError ex) { - LOG.log(Level.SEVERE, "kernel test failed with an assertion error"); + LOG.log(Level.SEVERE, "matrix3f test failed with an assertion error"); return false; } catch (Exception ex) { - LOG.log(Level.SEVERE, "kernel test failed with:", ex); + LOG.log(Level.SEVERE, "matrix3f test failed with:", ex); return false; } return true; @@ -392,10 +392,10 @@ public class TestOpenCLLibraries extends SimpleApplication { buffer.release(); } catch (AssertionError ex) { - LOG.log(Level.SEVERE, "kernel test failed with an assertion error"); + LOG.log(Level.SEVERE, "matrix4f test failed with an assertion error"); return false; } catch (Exception ex) { - LOG.log(Level.SEVERE, "kernel test failed with:", ex); + LOG.log(Level.SEVERE, "matrix4f test failed with:", ex); return false; } return true; diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java index 23cc4dda9..1085ad7d2 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclBuffer.java @@ -140,6 +140,7 @@ public class JoclBuffer extends Buffer { 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]); diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java index 252debdf3..ce6155928 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclImage.java @@ -448,6 +448,7 @@ public class JoclImage extends Image { 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]); diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java index 298a13059..ea0eb9543 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglBuffer.java @@ -136,6 +136,7 @@ public class LwjglBuffer extends Buffer { @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]); diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java index 5b9c06e66..ed9239677 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglImage.java @@ -449,6 +449,7 @@ public class LwjglImage extends Image { @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]); diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java index ce7bd8d0b..b3a668611 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglKernel.java @@ -162,8 +162,8 @@ public class LwjglKernel extends Kernel { 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.position(0); 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"); } From e32ebe11bba3cf3ff54c188e1abe37e5d677c6b7 Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Wed, 11 May 2016 09:42:11 +0200 Subject: [PATCH 35/40] fixed context creation for LWJGL3 --- .../com/jme3/system/lwjgl/LwjglContext.java | 37 ++++++++++--------- .../com/jme3/system/lwjgl/LwjglWindow.java | 7 ++++ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index cf32af063..72b1e934c 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -77,7 +77,7 @@ public abstract class LwjglContext implements JmeContext { //Fixme: OpenGL/CL sharing does not work yet, this line disables the sharing methods //(They will throw an OpenCLException) - public static final boolean CL_GL_SHARING_POSSIBLE = false; + public static final boolean CL_GL_SHARING_POSSIBLE = true; protected static final String THREAD_NAME = "jME3 Main"; @@ -198,12 +198,9 @@ public abstract class LwjglContext implements JmeContext { } renderable.set(true); - if (settings.isOpenCLSupport()) { - initOpenCL(); - } } - protected void initOpenCL() { + protected void initOpenCL(long window) { logger.info("Initialize OpenCL with LWJGL3"); // try { @@ -290,7 +287,7 @@ public abstract class LwjglContext implements JmeContext { //create context try { - long c = createContext(platform.getPlatform(), devices); + long c = createContext(platform.getPlatform(), devices, window); clContext = new com.jme3.opencl.lwjgl.LwjglContext(c, (List) choosenDevices); } catch (Exception ex) { logger.log(Level.SEVERE, "Unable to create OpenCL context", ex); @@ -299,7 +296,7 @@ public abstract class LwjglContext implements JmeContext { logger.info("OpenCL context created"); } - private long createContext(final CLPlatform platform, final List devices) throws Exception { + private long createContext(final CLPlatform platform, final List devices, long window) throws Exception { //Fixme: OpenGL/CL sharing does not work. The properties seem to be setup wrongly // If it works, set CL_GL_SHARING_POSSIBLE to true to enable the sharing @@ -311,27 +308,31 @@ public abstract class LwjglContext implements JmeContext { //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() ) { + switch (org.lwjgl.system.Platform.get()) { case WINDOWS: - long wglContext = org.lwjgl.opengl.WGL.wglGetCurrentContext(); - long wglDC = org.lwjgl.opengl.WGL.wglGetCurrentDC(); - properties.put(KHRGLSharing.CL_GL_CONTEXT_KHR).put(wglContext); - properties.put(KHRGLSharing.CL_WGL_HDC_KHR).put(wglDC); + 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.opengl.GLX.glXGetCurrentContext()); - properties.put(KHRGLSharing.CL_GLX_DISPLAY_KHR).put(org.lwjgl.opengl.GLX.glXGetCurrentDrawable()); + 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) + properties + .put(APPLEGLSharing.CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE) .put(org.lwjgl.opengl.CGL.CGLGetShareGroup(org.lwjgl.opengl.CGL.CGLGetCurrentContext())); - break; - default: - throw new UnsupportedOperationException("CL/GL context sharing is not supported on this platform."); } properties.put(CL_CONTEXT_PLATFORM).put(platform); properties.put(0); + properties.flip(); Utils.errorBuffer.rewind(); PointerBuffer deviceBuffer = PointerBuffer.allocateDirect(devices.size()); diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java index cac8ecdd1..6e351d8b2 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java @@ -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) { From bd491dc416552771d293843743f8211fd54e929c Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Wed, 11 May 2016 09:48:45 +0200 Subject: [PATCH 36/40] removed fixmes --- .../src/main/java/com/jme3/system/lwjgl/LwjglContext.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index 72b1e934c..9c31f2085 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -75,8 +75,6 @@ public abstract class LwjglContext implements JmeContext { private static final Logger logger = Logger.getLogger(LwjglContext.class.getName()); - //Fixme: OpenGL/CL sharing does not work yet, this line disables the sharing methods - //(They will throw an OpenCLException) public static final boolean CL_GL_SHARING_POSSIBLE = true; protected static final String THREAD_NAME = "jME3 Main"; @@ -298,10 +296,6 @@ public abstract class LwjglContext implements JmeContext { } private long createContext(final CLPlatform platform, final List devices, long window) throws Exception { - //Fixme: OpenGL/CL sharing does not work. The properties seem to be setup wrongly - // If it works, set CL_GL_SHARING_POSSIBLE to true to enable the sharing - // methods again - final int propertyCount = 2 + 4 + 1; final PointerBuffer properties = PointerBuffer.allocateDirect(propertyCount + devices.size()); From dd22ebefddc2d153bce2ae8b28798852eeeb9b9a Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Mon, 23 May 2016 08:07:42 +0200 Subject: [PATCH 37/40] Implemented Program.getBinary() with Jocl. The program cache now also works with Jocl. Thanks to @gouessej for his help. --- .../com/jme3/opencl/jocl/JoclContext.java | 17 +++++- .../com/jme3/opencl/jocl/JoclProgram.java | 52 +++++++++++++++---- .../com/jme3/opencl/lwjgl/LwjglContext.java | 4 +- .../com/jme3/opencl/lwjgl/LwjglContext.java | 4 +- 4 files changed, 61 insertions(+), 16 deletions(-) diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java index 163e27c68..d372587f1 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclContext.java @@ -224,8 +224,21 @@ public class JoclContext extends Context { @Override public Program createProgramFromBinary(ByteBuffer binaries, Device device) { - //Not supported because JoclProgram.getBinaries is also not supported. - throw new UnsupportedOperationException("No supported by Jocl"); + 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 { diff --git a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java index 157ce63cf..e64341876 100644 --- a/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java +++ b/jme3-jogl/src/main/java/com/jme3/opencl/jocl/JoclProgram.java @@ -32,6 +32,7 @@ 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; @@ -133,16 +134,47 @@ public class JoclProgram extends Program { } @Override - public ByteBuffer getBinary(Device device) { - //There is no way to do this in Jocl: - //The low-level bindings need a buffer of adresses to buffers. For that - //the class InternalBufferUtil is used, but this class is not public. - //I also can't create a temporal instance of CLProgram because the constructor - //that takes only the native pointer is private. - //So the only way would be to create the CLProgram directly from the beginning. - //I don't want to do this because then I would have to use the whole - //bunch of garbage the CLProgram class is doing in background. - throw new UnsupportedOperationException("Jocl does not expose this operation"); + 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 Date: Wed, 25 May 2016 13:29:49 +0200 Subject: [PATCH 38/40] Fixed Program.getBinary() for LWJGL3 --- .../com/jme3/opencl/lwjgl/LwjglProgram.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java index 15f46fc9c..eb8faa199 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/opencl/lwjgl/LwjglProgram.java @@ -86,12 +86,24 @@ public class LwjglProgram extends Program { } } + 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)); + //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(); @@ -122,8 +134,8 @@ public class LwjglProgram extends Program { @Override public ByteBuffer getBinary(Device d) { - throw new UnsupportedOperationException("Not supported yet, would crash the JVM"); - /* + //throw new UnsupportedOperationException("Not supported yet, would crash the JVM"); + LwjglDevice device = (LwjglDevice) d; int numDevices = Info.clGetProgramInfoInt(program, CL10.CL_PROGRAM_NUM_DEVICES); @@ -145,7 +157,7 @@ public class LwjglProgram extends Program { Utils.checkError(ret, "clGetProgramInfo: CL_PROGRAM_BINARY_SIZES"); int size = (int) sizes.get(index); - PointerBuffer binaryPointers = PointerBuffer.allocateDirect(numDevices * 8); + PointerBuffer binaryPointers = PointerBuffer.allocateDirect(numDevices); for (int i=0; i Date: Fri, 27 May 2016 10:32:49 +0200 Subject: [PATCH 39/40] added test for context switching. Changing the OpenCL platform and device by restarting the application works. --- .../jme3test/opencl/TestContextSwitching.java | 255 ++++++++++++++++++ .../opencl/ContextSwitchingScreen.xml | 27 ++ 2 files changed, 282 insertions(+) create mode 100644 jme3-examples/src/main/java/jme3test/opencl/TestContextSwitching.java create mode 100644 jme3-examples/src/main/resources/jme3test/opencl/ContextSwitchingScreen.xml diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestContextSwitching.java b/jme3-examples/src/main/java/jme3test/opencl/TestContextSwitching.java new file mode 100644 index 000000000..80be89cd7 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/opencl/TestContextSwitching.java @@ -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 platformListBox; + private ListBox deviceListBox; + + private static String selectedPlatform; + private static String selectedDevice; + private Context clContext; + private static List 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 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 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 chooseDevices(List 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); + } + + } +} diff --git a/jme3-examples/src/main/resources/jme3test/opencl/ContextSwitchingScreen.xml b/jme3-examples/src/main/resources/jme3test/opencl/ContextSwitchingScreen.xml new file mode 100644 index 000000000..6f57e96f1 --- /dev/null +++ b/jme3-examples/src/main/resources/jme3test/opencl/ContextSwitchingScreen.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From a834a4dad6061ebeb5b93e21ec502326c12dc94d Mon Sep 17 00:00:00 2001 From: shamanDevel Date: Fri, 27 May 2016 11:48:24 +0200 Subject: [PATCH 40/40] added test for multiple parallel applications: multiple OpenCL contexts do not work --- .../opencl/TestMultipleApplications.java | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 jme3-examples/src/main/java/jme3test/opencl/TestMultipleApplications.java diff --git a/jme3-examples/src/main/java/jme3test/opencl/TestMultipleApplications.java b/jme3-examples/src/main/java/jme3test/opencl/TestMultipleApplications.java new file mode 100644 index 000000000..1c2a5bf45 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/opencl/TestMultipleApplications.java @@ -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 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 chooseDevices(List 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"); + } + } + } +}