Package com.jme3.opencl
Activation:
OpenCL is deactivated by default. To activate it, set AppSettings.setOpenCLSupport(boolean)
to true
.
If the current platform supports OpenCL, then the central Context
can be fetched by JmeContext.getOpenCLContext()
which is
available in each application. If OpenCL is deactivated or not available,
this method returns null
.
First steps:
Once you have obtained your Context
you start by
creating a CommandQueue
by calling
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 Program
object
is created by Context.createProgramFromSourceCode(java.lang.String)
,
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 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: __kernel void KernelName(KernelArgs) {Code}
.
On the programming side, a Kernel
instance is obtained
by calling Program.createKernel(java.lang.String)
.
To execute the kernel, the method
Kernel.Run1(com.jme3.opencl.CommandQueue, com.jme3.opencl.Kernel.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 Buffer
instances are created by calling
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 __global float* buffer
.
Note that OpenCL does not check buffer boundaries. If you read or write outside
the buffer, the behavior is completely undefined and may often result in
a program cache later on.
Image
objects are structured one-, two-, or three-dimensional
memory chunks of a fixed type. They are created by Context.createImage().
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 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 -NoEvent
. This means that these methods
don't return an event object even if the OpenCL function would return an event.
There's 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 necessary.
Interoperability between OpenCL and jME3:
This Wrapper allows sharing jME3 Images and VertexBuffers with OpenCL.
VertexBuffer
objects can be shared with OpenCL
by calling Context.bindVertexBuffer(com.jme3.scene.VertexBuffer, com.jme3.opencl.MemoryAccess)
resulting in a Buffer
object. This buffer object
can then be used as usual, allowing e.g. the dynamic modification of position buffers for particle systems.
Image
and Texture
objects can be used in OpenCL with the method
Context.bindImage(com.jme3.texture.Texture, com.jme3.opencl.MemoryAccess)
or variations of this method. The same holds for FrameBuffer.RenderBuffer
objects
using 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 acquired explicitly
by Buffer.acquireBufferForSharingAsync(com.jme3.opencl.CommandQueue)
or Image.acquireImageForSharingAsync(com.jme3.opencl.CommandQueue)
.
After the work is done, release the resource with
Buffer.releaseBufferForSharingAsync(com.jme3.opencl.CommandQueue)
or 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
PlatformChooser
can be used by calling
AppSettings.setOpenCLPlatformChooser(java.lang.Class)
.
For more details, see the documentation of PlatformChooser
.
Exception handling:
All OpenCL-wrapper classes in this package
(this includes Platform
, Device
,
Context
, CommandQueue
,
Buffer
, Image
,
Program
, Kernel
and
Event
)
may throw the following exceptions in each method without being mentioned
explicitly in the documentation:
NullPointerException
: one of the arguments isnull
andnull
is not allowedIllegalArgumentException
: 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 sizeOpenCLException
: 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.
-
ClassDescriptionAbstract implementation of
OpenCLObject
providing the release mechanisms.Wrapper for an OpenCL buffer object.Result of an async mapping operation, contains the event and the target byte buffer.Wrapper for an OpenCL command queue.The central OpenCL context.A default implementation ofPlatformChooser
.Represents a hardware device actually running the OpenCL kernels.The device typeWrapper for an OpenCL Event object.Wrapper for an OpenCL image.ImageChannelOrder
specifies the number of channels and the channel layout i.e.ImageChannelType
describes the size of the channel data type.The image descriptor structure describes the type and dimensions of the image or image array.Describes the image format, consisting ofImage.ImageChannelOrder
andImage.ImageChannelType
.Describes a mapped region of the imageThe possible image types / dimensions.Wrapper for an OpenCL kernel, a piece of executable code on the GPU.A placeholder for kernel arguments representing local kernel memory.A placeholder for a kernel argument representing local kernel memory per thread.The work size (global and local) for executing a kernelThis exception is thrown byProgram.build()
when the compilation failed.Specifies how a buffer object can be accessed by the kernel.Generic OpenCL exception, can be thrown in every method of this package.Base interface of all native OpenCL objects.Releaser for anOpenCLObject
.A wrapper for an OpenCL platform.This SPI is called on startup to specify which platform and which devices are used for context creation.A wrapper for an OpenCL program.Implements a simple cache system for program objects.