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