|
|
|
@ -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() }. |
|
|
|
|
* <p> |
|
|
|
|
* The context is used to: |
|
|
|
|
* <ul> |
|
|
|
|
* <li>Query the available devices</li> |
|
|
|
|
* <li>Create a command queue</li> |
|
|
|
|
* <li>Create buffers and images</li> |
|
|
|
|
* <li>Created buffers and images shared with OpenGL vertex buffers, textures and renderbuffers</li> |
|
|
|
|
* <li>Create program objects from source code and source files</li> |
|
|
|
|
* </ul> |
|
|
|
|
* @author 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. |
|
|
|
|
* <br> |
|
|
|
|
* The available devices were specified by a {@link PlatformChooser}. |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
public abstract List<? extends Device> getDevices(); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Alternative version of {@link #createQueue(com.jme3.opencl.Device) }, |
|
|
|
|
* just uses the first device returned by {@link #getDevices() }. |
|
|
|
|
* @return the command queue |
|
|
|
|
*/ |
|
|
|
|
public CommandQueue createQueue() { |
|
|
|
|
return createQueue(getDevices().get(0)); |
|
|
|
|
} |
|
|
|
|
/** |
|
|
|
|
* Creates a command queue sending commands to the specified device. |
|
|
|
|
* The device must be an entry of {@link #getDevices() }. |
|
|
|
|
* @param device the target device |
|
|
|
|
* @return the command queue |
|
|
|
|
*/ |
|
|
|
|
public abstract CommandQueue createQueue(Device device); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Allocates a new buffer of the specific size and access type on the device. |
|
|
|
|
* @param size the size of the buffer in bytes |
|
|
|
|
* @param access the allowed access of this buffer from kernel code |
|
|
|
|
* @return the new buffer |
|
|
|
|
*/ |
|
|
|
|
public abstract Buffer createBuffer(long size, MemoryAccess access); |
|
|
|
|
/** |
|
|
|
|
* Alternative version of {@link #createBuffer(long, com.jme3.opencl.MemoryAccess) }, |
|
|
|
|
* creates a buffer with read and write access. |
|
|
|
|
* @param size the size of the buffer in bytes |
|
|
|
|
* @return the new buffer |
|
|
|
|
*/ |
|
|
|
|
public Buffer createBuffer(long size) { |
|
|
|
|
return createBuffer(size, MemoryAccess.READ_WRITE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Creates a new buffer wrapping the specific host memory. This host memory |
|
|
|
|
* specified by a ByteBuffer can then be used directly by kernel code, |
|
|
|
|
* although the access might be slower than with native buffers |
|
|
|
|
* created by {@link #createBuffer(long, com.jme3.opencl.MemoryAccess) }. |
|
|
|
|
* @param data the host buffer to use |
|
|
|
|
* @param access the allowed access of this buffer from kernel code |
|
|
|
|
* @return the new buffer |
|
|
|
|
*/ |
|
|
|
|
public abstract Buffer createBufferFromHost(ByteBuffer data, MemoryAccess access); |
|
|
|
|
/** |
|
|
|
|
* Alternative version of {@link #createBufferFromHost(java.nio.ByteBuffer, com.jme3.opencl.MemoryAccess) }, |
|
|
|
|
* creates a buffer with read and write access. |
|
|
|
|
* @param data the host buffer to use |
|
|
|
|
* @return the new buffer |
|
|
|
|
*/ |
|
|
|
|
public Buffer createBufferFromHost(ByteBuffer data) { |
|
|
|
|
return createBufferFromHost(data, MemoryAccess.READ_WRITE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public abstract Image createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr, ByteBuffer hostPtr); |
|
|
|
|
/** |
|
|
|
|
* Creates a new 1D, 2D, 3D image.<br> |
|
|
|
|
* {@code ImageFormat} specifies the element type and order, like RGBA of floats.<br> |
|
|
|
|
* {@code ImageDescriptor} specifies the dimension of the image.<br> |
|
|
|
|
* Furthermore, a ByteBuffer can be specified in the ImageDescriptor together |
|
|
|
|
* with row and slice pitches. This buffer is then used to store the image. |
|
|
|
|
* If no ByteBuffer is specified, a new buffer is allocated (this is the |
|
|
|
|
* normal behaviour). |
|
|
|
|
* @param access the allowed access of this image from kernel code |
|
|
|
|
* @param format the image format |
|
|
|
|
* @param descr the image descriptor |
|
|
|
|
* @return the new image object |
|
|
|
|
*/ |
|
|
|
|
public abstract Image createImage(MemoryAccess access, ImageFormat format, ImageDescriptor descr); |
|
|
|
|
//TODO: add simplified methods for 1D, 2D, 3D textures
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Queries all supported image formats for a specified memory access and |
|
|
|
|
* image type. |
|
|
|
|
* <br> |
|
|
|
|
* Note that the returned array may contain {@code ImageFormat} objects |
|
|
|
|
* where {@code ImageChannelType} or {@code ImageChannelOrder} are {@code null} |
|
|
|
|
* (or both). This is the case when the device supports new formats that |
|
|
|
|
* are not included in this wrapper yet. |
|
|
|
|
* @param access the memory access type |
|
|
|
|
* @param type the image type (1D, 2D, 3D, ...) |
|
|
|
|
* @return an array of all supported image formats |
|
|
|
|
*/ |
|
|
|
|
public abstract ImageFormat[] querySupportedFormats(MemoryAccess access, ImageType type); |
|
|
|
|
|
|
|
|
|
//Interop
|
|
|
|
|
/** |
|
|
|
|
* Creates a shared buffer from a VertexBuffer. |
|
|
|
|
* The returned buffer and the vertex buffer operate on the same memory, |
|
|
|
|
* changes in one view are visible in the other view. |
|
|
|
|
* This can be used to modify meshes directly from OpenCL (e.g. for particle systems). |
|
|
|
|
* <br> |
|
|
|
|
* <b>Note:</b> The vertex buffer must already been uploaded to the GPU, |
|
|
|
|
* i.e. it must be used at least once for drawing. |
|
|
|
|
* <p> |
|
|
|
|
* Before the returned buffer can be used, it must be acquried explicitly |
|
|
|
|
* by {@link Buffer#acquireBufferForSharingAsync(com.jme3.opencl.CommandQueue) } |
|
|
|
|
* and after modifying it, released by {@link Buffer#releaseBufferForSharingAsync(com.jme3.opencl.CommandQueue) }. |
|
|
|
|
* This is needed so that OpenGL and OpenCL operations do not interfer with each other. |
|
|
|
|
* @param vb the vertex buffer to share |
|
|
|
|
* @param access the memory access for the kernel |
|
|
|
|
* @return the new buffer |
|
|
|
|
*/ |
|
|
|
|
public abstract Buffer bindVertexBuffer(VertexBuffer vb, MemoryAccess access); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Creates a shared image object from a jME3-image. |
|
|
|
|
* The returned image shares the same memory with the jME3-image, changes |
|
|
|
|
* in one view are visible in the other view. |
|
|
|
|
* This can be used to modify textures and images directly from OpenCL |
|
|
|
|
* (e.g. for post processing effects and other texture effects). |
|
|
|
|
* <br> |
|
|
|
|
* <b>Note:</b> The image must already been uploaded to the GPU, |
|
|
|
|
* i.e. it must be used at least once for drawing. |
|
|
|
|
* <p> |
|
|
|
|
* Before the returned image can be used, it must be acquried explicitly |
|
|
|
|
* by {@link Image#acquireImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
|
|
|
|
* and after modifying it, released by {@link Image#releaseImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
|
|
|
|
* This is needed so that OpenGL and OpenCL operations do not interfer with each other. |
|
|
|
|
* |
|
|
|
|
* @param image the jME3 image object |
|
|
|
|
* @param textureType the texture type (1D, 2D, 3D), since this is not stored in the image |
|
|
|
|
* @param miplevel the mipmap level that should be shared |
|
|
|
|
* @param access the allowed memory access for kernels |
|
|
|
|
* @return the OpenCL image |
|
|
|
|
*/ |
|
|
|
|
public abstract Image bindImage(com.jme3.texture.Image image, Texture.Type textureType, int miplevel, MemoryAccess access); |
|
|
|
|
/** |
|
|
|
|
* Creates a shared image object from a jME3 texture. |
|
|
|
|
* The returned image shares the same memory with the jME3 texture, changes |
|
|
|
|
* in one view are visible in the other view. |
|
|
|
|
* This can be used to modify textures and images directly from OpenCL |
|
|
|
|
* (e.g. for post processing effects and other texture effects). |
|
|
|
|
* <br> |
|
|
|
|
* <b>Note:</b> The image must already been uploaded to the GPU, |
|
|
|
|
* i.e. it must be used at least once for drawing. |
|
|
|
|
* <p> |
|
|
|
|
* Before the returned image can be used, it must be acquried explicitly |
|
|
|
|
* by {@link Image#acquireImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
|
|
|
|
* and after modifying it, released by {@link Image#releaseImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
|
|
|
|
* This is needed so that OpenGL and OpenCL operations do not interfer with each other. |
|
|
|
|
* <p> |
|
|
|
|
* This method is equivalent to calling |
|
|
|
|
* {@code bindImage(texture.getImage(), texture.getType(), miplevel, access)}. |
|
|
|
|
* |
|
|
|
|
* @param texture the jME3 texture |
|
|
|
|
* @param miplevel the mipmap level that should be shared |
|
|
|
|
* @param access the allowed memory access for kernels |
|
|
|
|
* @return the OpenCL image |
|
|
|
|
*/ |
|
|
|
|
public Image bindImage(Texture texture, int miplevel, MemoryAccess access) { |
|
|
|
|
return bindImage(texture.getImage(), texture.getType(), miplevel, access); |
|
|
|
|
} |
|
|
|
|
/** |
|
|
|
|
* Alternative version to {@link #bindImage(com.jme3.texture.Texture, int, com.jme3.opencl.MemoryAccess) }, |
|
|
|
|
* uses {@code miplevel=0}. |
|
|
|
|
* @param texture the jME3 texture |
|
|
|
|
* @param access the allowed memory access for kernels |
|
|
|
|
* @return the OpenCL image |
|
|
|
|
*/ |
|
|
|
|
public Image bindImage(Texture texture, MemoryAccess access) { |
|
|
|
|
return bindImage(texture, 0, access); |
|
|
|
|
} |
|
|
|
|
/** |
|
|
|
|
* Creates a shared image object from a jME3 render buffer. |
|
|
|
|
* The returned image shares the same memory with the jME3 render buffer, changes |
|
|
|
|
* in one view are visible in the other view. |
|
|
|
|
* <br> |
|
|
|
|
* This can be used as an alternative to post processing effects |
|
|
|
|
* (e.g. reduce sum operations, needed e.g. for tone mapping). |
|
|
|
|
* <br> |
|
|
|
|
* <b>Note:</b> The renderbuffer must already been uploaded to the GPU, |
|
|
|
|
* i.e. it must be used at least once for drawing. |
|
|
|
|
* <p> |
|
|
|
|
* Before the returned image can be used, it must be acquried explicitly |
|
|
|
|
* by {@link Image#acquireImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
|
|
|
|
* and after modifying it, released by {@link Image#releaseImageForSharingAsync(com.jme3.opencl.CommandQueue) } |
|
|
|
|
* This is needed so that OpenGL and OpenCL operations do not interfer with each other. |
|
|
|
|
* |
|
|
|
|
* @param buffer |
|
|
|
|
* @param access |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
public Image bindRenderBuffer(FrameBuffer.RenderBuffer buffer, MemoryAccess access) { |
|
|
|
|
if (buffer.getTexture() == null) { |
|
|
|
|
return bindPureRenderBuffer(buffer, access); |
|
|
|
@ -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. |
|
|
|
|
* <p> |
|
|
|
|
* The typical use case is: |
|
|
|
|
* <ul> |
|
|
|
|
* <li>The include string contains some compiler constants like the grid size </li> |
|
|
|
|
* <li>Some common OpenCL files used as libraries (Convention: file names end with {@code .clh}</li> |
|
|
|
|
* <li>One main OpenCL file containing the actual kernels (Convention: file name ends with {@code .cl})</li> |
|
|
|
|
* </ul> |
|
|
|
|
* Note: Files that can't be loaded are skipped.<br> |
|
|
|
|
* |
|
|
|
|
* 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. |
|
|
|
|
* <p> |
|
|
|
|
* The typical use case is: |
|
|
|
|
* <ul> |
|
|
|
|
* <li>The include string contains some compiler constants like the grid size </li> |
|
|
|
|
* <li>Some common OpenCL files used as libraries (Convention: file names end with {@code .clh}</li> |
|
|
|
|
* <li>One main OpenCL file containing the actual kernels (Convention: file name ends with {@code .cl})</li> |
|
|
|
|
* </ul> |
|
|
|
|
* Note: Files that can't be loaded are skipped.<br> |
|
|
|
|
* |
|
|
|
|
* 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<String> 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<String> resources) { |
|
|
|
|
return createProgramFromSourceFilesWithInclude(assetManager, "", resources); |
|
|
|
|
} |
|
|
|
|