/*
 * Copyright (c) 2009-2021 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * This package contains an API for using OpenCL together with jME3.
 * <p>
 * <b>Activation:</b><br>
 * OpenCL is deactivated by default. To activate it, set {@link com.jme3.system.AppSettings#setOpenCLSupport(boolean) }
 * to {@code true}.
 * If the current platform supports OpenCL, then the central {@link com.jme3.opencl.Context} 
 * can be fetched by {@link com.jme3.system.JmeContext#getOpenCLContext() } which is
 * available in each application. If OpenCL is deactivated or not available, 
 * this method returns {@code null}.
 * 
 * <p>
 * <b>First steps:</b><br>
 * Once you have obtained your {@link com.jme3.opencl.Context} you start by
 * creating a {@link com.jme3.opencl.CommandQueue} by calling 
 * {@link com.jme3.opencl.Context#createQueue() } or alternative versions.
 * The command queue must be passed to every following method that execute
 * some action involving the GPU. All actions are executed in the order in which they
 * are added to the queue.
 * <br>
 * <b>Programs and Kernels:</b>
 * The main purpose of OpenCL is to execute code in parallel
 * on the GPU. From the source code, a {@link com.jme3.opencl.Program} object
 * is created by {@link com.jme3.opencl.Context#createProgramFromSourceCode(java.lang.String) },
 * {@link com.jme3.opencl.Context#createProgramFromSourceFilesWithInclude(com.jme3.asset.AssetManager, java.lang.String, java.util.List) }
 * or alternative versions.
 * Before using it, the source code must be build using {@link com.jme3.opencl.Program#build() }.
 * Any compilation error is thrown here. Each program consists of multiple kernels.
 * Each kernel represents one executable unit and is declared in the source code
 * with the following syntax: {@code __kernel void KernelName(KernelArgs) {Code} }.
 * On the programming side, a {@link com.jme3.opencl.Kernel} instance is obtained
 * by calling {@link com.jme3.opencl.Program#createKernel(java.lang.String) }.
 * To execute the kernel, the method
 * {@link com.jme3.opencl.Kernel#Run1(com.jme3.opencl.CommandQueue, com.jme3.opencl.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.
 * <br>
 * <b>Buffers and Images:</b>
 * OpenCL Kernels show their true power first when they operate on buffers and images.
 * Buffers are simple one dimensional consecutive chunks of memory of arbitrary size.
 * These {@link com.jme3.opencl.Buffer} instances are created by calling
 * {@link com.jme3.opencl.Context#createBuffer(long)} with the size in bytes as
 * the argument. A buffer on its own is typeless. In the kernel, you then specify
 * the type of the buffer by argument declarations like {@code __global float* buffer}.
 * Note that OpenCL does not check buffer boundaries. If you read or write outside
 * 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 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.
 * <br>
 * <b>Events:</b>
 * Most methods are provided in two variations: blocking calls or asynchronous
 * calls (the later one have the suffix -Async, or all kernel calls).
 * These async calls all return {@link com.jme3.opencl.Event} objects.
 * These events can be used to check (non-blocking) if the action has completed, e.g. a memory copy
 * is finished, or to block the execution until the action has finished.
 * <br>
 * Some methods have the suffix {@code -NoEvent}. This means that these methods
 * don't return an event object even if the OpenCL function would return an event.
 * There'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.
 * 
 * <p>
 * <b>Interoperability between OpenCL and jME3:</b><br>
 * This Wrapper allows sharing jME3 Images and VertexBuffers with OpenCL.<br>
 * {@link com.jme3.scene.VertexBuffer} objects can be shared with OpenCL
 * by calling {@link com.jme3.opencl.Context#bindVertexBuffer(com.jme3.scene.VertexBuffer, com.jme3.opencl.MemoryAccess) }
 * resulting in a {@link com.jme3.opencl.Buffer} object. This buffer object
 * can then be used as usual, allowing e.g. the dynamic modification of position buffers for particle systems.<br>
 * {@link com.jme3.texture.Image} and {@link com.jme3.texture.Texture} objects can be used in OpenCL with the method
 * {@link com.jme3.opencl.Context#bindImage(com.jme3.texture.Texture, com.jme3.opencl.MemoryAccess) }
 * or variations of this method. The same holds for {@link com.jme3.texture.FrameBuffer.RenderBuffer} objects
 * using {@link com.jme3.opencl.Context#bindRenderBuffer(com.jme3.texture.FrameBuffer.RenderBuffer, com.jme3.opencl.MemoryAccess) }.
 * These methods result in an OpenCL-Image. Usages are e.g. animated textures,
 * terrain based on height maps, post-processing effects, and so forth.
 * <br>
 * <i>Important:</i> Before shared objects can be used by any OpenCL function
 * like kernel calls or read/write/copy methods, they must be acquired explicitly
 * by {@link com.jme3.opencl.Buffer#acquireBufferForSharingAsync(com.jme3.opencl.CommandQueue) }
 * or {@link com.jme3.opencl.Image#acquireImageForSharingAsync(com.jme3.opencl.CommandQueue) }.
 * After the work is done, release the resource with
 * {@link com.jme3.opencl.Buffer#releaseBufferForSharingAsync(com.jme3.opencl.CommandQueue) }
 * or {@link com.jme3.opencl.Image#releaseImageForSharingAsync(com.jme3.opencl.CommandQueue) }.
 * This ensures the synchronization of OpenCL and OpenGL.
 * 
 * <p>
 * <b>Experts: choosing the right platform and devices</b><br>
 * OpenCL can run on different platforms and different devices. On some systems,
 * like multi-GPU setups, this choice really matters. To specify which platform
 * and which devices are used, a custom implementation of 
 * {@link com.jme3.opencl.PlatformChooser} can be used by calling
 * {@link com.jme3.system.AppSettings#setOpenCLPlatformChooser(java.lang.Class) }.
 * For more details, see the documentation of {@code PlatformChooser}.
 * 
 * <p>
 * <b>Exception handling:</b><br>
 * All OpenCL-wrapper classes in this package
 * (this includes {@link com.jme3.opencl.Platform}, {@link com.jme3.opencl.Device},
 * {@link com.jme3.opencl.Context}, {@link com.jme3.opencl.CommandQueue},
 * {@link com.jme3.opencl.Buffer}, {@link com.jme3.opencl.Image},
 * {@link com.jme3.opencl.Program}, {@link com.jme3.opencl.Kernel} and
 * {@link com.jme3.opencl.Event})
 * may throw the following exceptions in each method without being mentioned 
 * explicitly in the documentation:
 * <ul>
 * <li>{@code NullPointerException}: one of the arguments is {@code null} and 
 * {@code null} is not allowed</li>
 * <li>{@code IllegalArgumentException}: the arguments don't follow the rules
 * as specified in the documentation of the method, e.g. values are out of range
 * or an array has the wrong size</li>
 * <li>{@link com.jme3.opencl.OpenCLException}: some low-level exception was
 * thrown. The exception always records the error code and error name and the 
 * OpenCL function call where the error was detected. Please check the official
 * OpenCL specification for the meanings of these errors for that particular function.</li>
 * </ul>
 */
package com.jme3.opencl;

//TODO: add profiling to Kernel, CommandQueue
