com.jme3.opencl.Image Maven / Gradle / Ivy
Show all versions of jme3-core Show documentation
/*
* Copyright (c) 2009-2020 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.ColorRGBA;
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 type and dimensions 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 shaman
*/
public abstract class Image extends AbstractOpenCLObject {
/**
* {@code ImageChannelType} describes the size of the channel data type.
*/
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
}
/**
* {@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,
LUMINANCE,
RG, RGx, RA,
RGB, RGBx,
RGBA,
ARGB, BGRA
}
/**
* Describes the image format, consisting of
* {@link ImageChannelOrder} and {@link ImageChannelType}.
*/
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;
}
}
/**
* The possible image types / dimensions.
*/
public static enum ImageType {
IMAGE_1D,
IMAGE_1D_BUFFER,
IMAGE_2D,
IMAGE_3D,
IMAGE_1D_ARRAY,
IMAGE_2D_ARRAY
}
/**
* The image descriptor structure describes the type and dimensions of the image or image array.
*
* There exist two constructors:
* ImageDescriptor(ImageType, long, long, long, long)
* is used when an image with new memory should be created (used most often).
* ImageDescriptor(ImageType, long, long, long, long, long, long, ByteBuffer)
* creates an image using the provided {@code ByteBuffer} as source.
*/
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 ByteBuffer hostPtr;
/*
public int numMipLevels; //They must always be set to zero
public int numSamples;
*/
public ImageDescriptor() {
}
/**
* Used to specify an image with the provided ByteBuffer as source
*
* @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;
this.height = height;
this.depth = depth;
this.arraySize = arraySize;
this.rowPitch = rowPitch;
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;
this.height = height;
this.depth = depth;
this.arraySize = arraySize;
this.rowPitch = 0;
this.slicePitch = 0;
hostPtr = null;
}
@Override
public String toString() {
return "ImageDescriptor{" + "type=" + type + ", width=" + width + ", height=" + height + ", depth=" + depth + ", arraySize=" + arraySize + ", rowPitch=" + rowPitch + ", slicePitch=" + slicePitch + '}';
}
}
protected Image(ObjectReleaser releaser) {
super(releaser);
}
@Override
public Image register() {
super.register();
return this;
}
/**
* @return the width of the image
*/
public abstract long getWidth();
/**
* @return the height of the image
*/
public abstract long getHeight();
/**
* @return the depth of the image
*/
public abstract long getDepth();
/**
* @return the row pitch when the image was created from a host buffer
*/
public abstract long getRowPitch();
/**
* @return the slice pitch when the image was created from a host buffer
*/
public abstract long getSlicePitch();
/**
* @return the number of elements in the image array
* @see ImageType#IMAGE_1D_ARRAY
* @see ImageType#IMAGE_2D_ARRAY
*/
public abstract long getArraySize();
/**
* @return the image format
*/
public abstract ImageFormat getImageFormat();
/**
* @return the image type
*/
public abstract ImageType getImageType();
/**
* @return the number of bytes per pixel
*/
public abstract 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}
*/
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
* @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
*/
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.
*
* @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}
*/
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
* @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
*/
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.
* 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
*/
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!
*
* @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
*/
public abstract 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 async
* 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)
*/
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.
* 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)
*/
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
*/
public abstract 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) {
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 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
*/
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}
* or {@link ImageChannelType#HALF_FLOAT}.
*
* @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
*/
public abstract 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
*/
public abstract Event copyToBufferAsync(CommandQueue queue, Buffer dest, long[] srcOrigin, long[] srcRegion, long destOffset);
/**
* Acquires 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
*/
public abstract Event acquireImageForSharingAsync(CommandQueue queue);
/**
* Acquires 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
* {@link #acquireImageForSharingAsync(com.jme3.opencl.CommandQueue) }
* to hand the control back to OpenGL.
*
* @param queue the command queue
* @return the event object
*/
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();
}
@Override
public String toString() {
StringBuilder str = new StringBuilder();
str.append("Image (");
ImageType t = getImageType();
str.append(t);
str.append(", w=").append(getWidth());
if (t == ImageType.IMAGE_2D || t == ImageType.IMAGE_3D) {
str.append(", h=").append(getHeight());
}
if (t == ImageType.IMAGE_3D) {
str.append(", d=").append(getDepth());
}
if (t == ImageType.IMAGE_1D_ARRAY || t == ImageType.IMAGE_2D_ARRAY) {
str.append(", arrays=").append(getArraySize());
}
str.append(", ").append(getImageFormat());
str.append(')');
return str.toString();
}
}