org.lwjgl.BufferUtils Maven / Gradle / Ivy
Show all versions of org.lwjgl.lwjgl Show documentation
/*
* Copyright LWJGL. All rights reserved.
* License terms: https://www.lwjgl.org/license
*/
package org.lwjgl;
import org.lwjgl.system.*;
import java.nio.*;
import static org.lwjgl.system.APIUtil.*;
import static org.lwjgl.system.MemoryUtil.*;
/**
* This class makes it easy and safe to work with direct buffers. It is the recommended way to allocate memory to use with LWJGL.
*
* Direct buffers
*
* LWJGL requires that all NIO buffers passed to it are direct buffers. Direct buffers essentially wrap an address that points to off-heap memory, i.e. a
* native pointer. This is the only way LWJGL can safely pass data from Java code to native code, and vice-versa, without a performance penalty. It does not
* support on-heap Java arrays (or plain NIO buffers, which wrap them) because arrays may be moved around in memory by the JVM's garbage collector while native
* code is accessing them. In addition, Java arrays have an unspecified layout, i.e. they are not necessarily contiguous in memory.
*
* Usage
*
* When a direct buffer is passed as an argument to an LWJGL method, no data is copied. Instead, the current buffer position is added to the buffer's memory
* address and the resulting value is passed to native code. The native code interprets that value as a pointer and reads or copies from it as necessary. LWJGL
* will often also use the current buffer limit (via {@link Buffer#remaining()}) to automatically pass length/maxlength arguments. This means that, just like
* other APIs that use NIO buffers, the current {@link Buffer#position()} and {@link Buffer#limit()} at the time of the call is very important. Contrary to
* other APIs, LWJGL never modifies the current position, it will be the same value before and after the call.
*
* Arrays of pointers
*
* In addition to the standard NIO buffer classes, LWJGL provides a {@link PointerBuffer} class for storing pointer data in an architecture independent way.
* It is used in bindings for pointer-to-pointers arguments, usually to provide arrays of data (input parameter) or to store returned pointer values (output
* parameter). Also, there's the {@link CLongBuffer} class which is similar to {@code PointerBuffer}, but for C {@code long} data.
*
* Memory management
*
* Using NIO buffers for off-heap memory has some drawbacks:
*
* - Memory blocks bigger than {@link Integer#MAX_VALUE} bytes cannot be allocated.
* - Memory blocks are zeroed-out on allocation, for safety. This has (sometimes unwanted) performance implications.
* - There is no way to free a buffer explicitly (without JVM specific reflection). Buffer objects are subject to GC and it usually takes two GC cycles to
* free the off-heap memory after the buffer object becomes unreachable.
*
*
* An alternative API for allocating off-heap memory can be found in the {@link org.lwjgl.system.MemoryUtil} class. This has none of the above drawbacks,
* but requires allocated memory to be explictly freed when not used anymore.
*
* Memory alignment
*
* Allocations done via this class have a guaranteed alignment of 8 bytes. If higher alignment values are required, use the explicit memory management API
* or pad the requested memory with extra bytes and align manually.
*
* Structs and arrays of structs
*
* Java does not support struct value types, so LWJGL requires struct values that are backed by off-heap memory. Each struct type defined in a binding
* has a corresponding class in LWJGL that can be used to access its members. Each struct class also has a {@code Buffer} inner class that can be used to
* access (packed) arrays of struct values. Both struct and struct buffer classes may be backed by direct {@link ByteBuffer}s allocated from this class, but it
* is highly recommended to use explicit memory management for performance.
*/
public final class BufferUtils {
private BufferUtils() {}
/**
* Allocates a direct native-ordered {@code ByteBuffer} with the specified capacity.
*
* @param capacity the capacity, in bytes
*
* @return a {@code ByteBuffer}
*/
public static ByteBuffer createByteBuffer(int capacity) {
return ByteBuffer.allocateDirect(capacity).order(ByteOrder.nativeOrder());
}
static int getAllocationSize(int elements, int elementShift) {
apiCheckAllocation(elements, apiGetBytes(elements, elementShift), 0x7FFF_FFFFL);
return elements << elementShift;
}
/**
* Allocates a direct native-order {@code ShortBuffer} with the specified number of elements.
*
* @param capacity the capacity, in shorts
*
* @return a {@code ShortBuffer}
*/
public static ShortBuffer createShortBuffer(int capacity) {
return createByteBuffer(getAllocationSize(capacity, 1)).asShortBuffer();
}
/**
* Allocates a direct native-order {@code CharBuffer} with the specified number of elements.
*
* @param capacity the capacity, in chars
*
* @return a {@code CharBuffer}
*/
public static CharBuffer createCharBuffer(int capacity) {
return createByteBuffer(getAllocationSize(capacity, 1)).asCharBuffer();
}
/**
* Allocates a direct native-order {@code IntBuffer} with the specified number of elements.
*
* @param capacity the capacity, in ints
*
* @return an {@code IntBuffer}
*/
public static IntBuffer createIntBuffer(int capacity) {
return createByteBuffer(getAllocationSize(capacity, 2)).asIntBuffer();
}
/**
* Allocates a direct native-order {@code LongBuffer} with the specified number of elements.
*
* @param capacity the capacity, in longs
*
* @return a {@code LongBuffer}
*/
public static LongBuffer createLongBuffer(int capacity) {
return createByteBuffer(getAllocationSize(capacity, 3)).asLongBuffer();
}
/**
* Allocates a {@code CLongBuffer} with the specified number of elements.
*
* @param capacity the capacity, in memory addresses
*
* @return a {@code CLongBuffer}
*/
public static CLongBuffer createCLongBuffer(int capacity) {
return CLongBuffer.allocateDirect(capacity);
}
/**
* Allocates a direct native-order {@code FloatBuffer} with the specified number of elements.
*
* @param capacity the capacity, in floats
*
* @return a FloatBuffer
*/
public static FloatBuffer createFloatBuffer(int capacity) {
return createByteBuffer(getAllocationSize(capacity, 2)).asFloatBuffer();
}
/**
* Allocates a direct native-order {@code DoubleBuffer} with the specified number of elements.
*
* @param capacity the capacity, in doubles
*
* @return a {@code DoubleBuffer}
*/
public static DoubleBuffer createDoubleBuffer(int capacity) {
return createByteBuffer(getAllocationSize(capacity, 3)).asDoubleBuffer();
}
/**
* Allocates a {@code PointerBuffer} with the specified number of elements.
*
* @param capacity the capacity, in memory addresses
*
* @return a {@code PointerBuffer}
*/
public static PointerBuffer createPointerBuffer(int capacity) {
return PointerBuffer.allocateDirect(capacity);
}
// memsets
/**
* Fills the specified buffer with zeros from the current position to the current limit.
*
* @param buffer the buffer to fill with zeros
*/
public static void zeroBuffer(ByteBuffer buffer) { memSet(buffer, 0); }
/**
* Fills the specified buffer with zeros from the current position to the current limit.
*
* @param buffer the buffer to fill with zeros
*/
public static void zeroBuffer(ShortBuffer buffer) { memSet(buffer, 0); }
/**
* Fills the specified buffer with zeros from the current position to the current limit.
*
* @param buffer the buffer to fill with zeros
*/
public static void zeroBuffer(CharBuffer buffer) { memSet(buffer, 0); }
/**
* Fills the specified buffer with zeros from the current position to the current limit.
*
* @param buffer the buffer to fill with zeros
*/
public static void zeroBuffer(IntBuffer buffer) { memSet(buffer, 0); }
/**
* Fills the specified buffer with zeros from the current position to the current limit.
*
* @param buffer the buffer to fill with zeros
*/
public static void zeroBuffer(FloatBuffer buffer) { memSet(buffer, 0); }
/**
* Fills the specified buffer with zeros from the current position to the current limit.
*
* @param buffer the buffer to fill with zeros
*/
public static void zeroBuffer(LongBuffer buffer) { memSet(buffer, 0); }
/**
* Fills the specified buffer with zeros from the current position to the current limit.
*
* @param buffer the buffer to fill with zeros
*/
public static void zeroBuffer(DoubleBuffer buffer) { memSet(buffer, 0); }
/**
* Fills the specified buffer with zeros from the current position to the current limit.
*
* @param buffer the buffer to fill with zeros
*/
public static > void zeroBuffer(T buffer) { memSet(buffer, 0); }
}