From 3c822cbec0c534f346af1a6e341ea6339a82d801 Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Fri, 22 Nov 2024 11:50:18 -0500 Subject: [PATCH 1/8] Initial MemoryStack backport --- .../compat/lwjgl/CompatMemoryUtil.java | 82 ++ .../angelica/compat/lwjgl/MemoryStack.java | 1058 +++++++++++++++++ .../angelica/compat/lwjgl/Pointer.java | 93 ++ 3 files changed, 1233 insertions(+) create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java create mode 100644 src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/Pointer.java diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java index 6b311ca88..f7b0aac41 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java @@ -1,5 +1,8 @@ package com.gtnewhorizons.angelica.compat.lwjgl; +import static com.gtnewhorizons.angelica.compat.lwjgl.Pointer.BITS64; +import static org.lwjgl.MemoryUtil.getAddress; + import org.lwjgl.BufferUtils; import java.nio.ByteBuffer; @@ -7,6 +10,8 @@ import java.nio.IntBuffer; public class CompatMemoryUtil { + public static final long NULL = 0; + public static ByteBuffer memReallocDirect(ByteBuffer old, int capacity) { ByteBuffer newBuf = BufferUtils.createByteBuffer(capacity); int oldPos = old.position(); @@ -99,4 +104,81 @@ private static sun.misc.Unsafe getUnsafeInstance() { public static float memGetFloat(long ptr) { return UNSAFE.getFloat(null, ptr); } public static double memGetDouble(long ptr) { return UNSAFE.getDouble(null, ptr); } + /** + * Sets all bytes in a specified block of memory to a fixed value (usually zero). + * + * @param ptr the starting memory address + * @param value the value to set (memSet will convert it to unsigned byte) + */ + public static void memSet(ByteBuffer ptr, int value) { memSet(getAddress(ptr), value, ptr.remaining()); } + + + private static final int FILL_PATTERN_32 = Integer.divideUnsigned(-1, 255); + private static final long FILL_PATTERN_64 = Long.divideUnsigned(-1L, 255L); + + /** + * Sets all bytes in a specified block of memory to a fixed value (usually zero). + * + * @param ptr the starting memory address + * @param value the value to set (memSet will convert it to unsigned byte) + * @param bytes the number of bytes to set + */ + public static void memSet(long ptr, int value, long bytes) { + if (/*DEBUG*/ false && (ptr == NULL || bytes < 0)) { + throw new IllegalArgumentException(); + } + + /* + - Unsafe.setMemory is very slow. + - A custom Java loop is fastest at small sizes, approximately up to 256 bytes. + - The native memset becomes fastest at bigger sizes, when the JNI overhead becomes negligible. + */ + + //UNSAFE.setMemory(ptr, bytes, (byte)(value & 0xFF)); + //if (bytes < 256L) { + int p = (int)ptr; + if (BITS64) { + if ((p & 7) == 0) { + memSet64(ptr, value, (int)bytes & 0xFF); + return; + } + } else { + if ((p & 3) == 0) { + memSet32(p, value, (int)bytes & 0xFF); + return; + } + } + //} + //nmemset(ptr, value, bytes); + } + private static void memSet64(long ptr, int value, int bytes) { + int aligned = bytes & ~7; + + // Aligned body + long valuel = (value & 0xFF) * FILL_PATTERN_64; + for (int i = 0; i < aligned; i += 8) { + UNSAFE.putLong(null, ptr + i, valuel); + } + + // Unaligned tail + byte valueb = (byte)(value & 0xFF); + for (int i = aligned; i < bytes; i++) { + UNSAFE.putByte(null, ptr + i, valueb); + } + } + private static void memSet32(int ptr, int value, int bytes) { + int aligned = bytes & ~3; + + // Aligned body + int vi = (value & 0xFF) * FILL_PATTERN_32; + for (int i = 0; i < aligned; i += 4) { + UNSAFE.putInt(null, (ptr + i) & 0xFFFF_FFFFL, vi); + } + + // Unaligned tail + byte vb = (byte)(value & 0xFF); + for (int i = aligned; i < bytes; i++) { + UNSAFE.putByte(null, (ptr + i) & 0xFFFF_FFFFL, vb); + } + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java new file mode 100644 index 000000000..ac6a2b295 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java @@ -0,0 +1,1058 @@ +/* + * This class is backported from LWJGL3 under the BSD 3-clause "New" or "Revised" License + */ + +package com.gtnewhorizons.angelica.compat.lwjgl; + + +import com.gtnewhorizons.angelica.loading.AngelicaTweaker; +import java.nio.ByteBuffer; +import java.util.Arrays; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.BufferUtils; +import org.lwjgl.MemoryUtil; + +/** + * An off-heap memory stack. + * + *

This class should be used in a thread-local manner for stack allocations.

+ * + * @ see Configuration#STACK_SIZE + * @ see Configuration#DEBUG_STACK + */ +public class MemoryStack extends Pointer.Default implements AutoCloseable { + + private static final int DEFAULT_STACK_SIZE = /*Configuration.STACK_SIZE.get(64)*/ 64 * 1024; + private static final int DEFAULT_STACK_FRAMES = 8; + + private static final ThreadLocal TLS = ThreadLocal.withInitial(MemoryStack::create); + + static { + if (DEFAULT_STACK_SIZE < 0) { + throw new IllegalStateException("Invalid stack size."); + } + } + + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + private final @Nullable ByteBuffer container; + + private final int size; + + private int pointer; + + private int[] frames; + protected int frameIndex; + + /** + * Creates a new {@code MemoryStack} backed by the specified memory region. + * + *

In the initial state, there is no active stack frame. The {@link #push} method must be used before any allocations.

+ * + * @param container the backing memory buffer, may be null + * @param address the backing memory address + * @param size the backing memory size + */ + protected MemoryStack(@Nullable ByteBuffer container, long address, int size) { + super(address); + this.container = container; + + this.size = size; + this.pointer = size; + + this.frames = new int[DEFAULT_STACK_FRAMES]; + } + + /** + * Creates a new {@code MemoryStack} with the default size. + * + *

In the initial state, there is no active stack frame. The {@link #push} method must be used before any allocations.

+ */ + public static MemoryStack create() { + return create(DEFAULT_STACK_SIZE); + } + + /** + * Creates a new {@code MemoryStack} with the specified size. + * + *

In the initial state, there is no active stack frame. The {@link #push} method must be used before any allocations.

+ * + * @param capacity the maximum number of bytes that may be allocated on the stack + */ + public static MemoryStack create(int capacity) { + return create(BufferUtils.createByteBuffer(capacity)); + } + + /** + * Creates a new {@code MemoryStack} backed by the specified memory buffer. + * + *

In the initial state, there is no active stack frame. The {@link #push} method must be used before any allocations.

+ * + * @param buffer the backing memory buffer + */ + public static MemoryStack create(ByteBuffer buffer) { + long address = MemoryUtil.getAddress(buffer); + int size = buffer.remaining(); + return new MemoryStack(buffer, address, size); + } + + /** + * Creates a new {@code MemoryStack} backed by the specified memory region. + * + *

In the initial state, there is no active stack frame. The {@link #push} method must be used before any allocations.

+ * + * @param address the backing memory address + * @param size the backing memory size + */ + public static MemoryStack ncreate(long address, int size) { + return new MemoryStack(null, address, size); + } + + /** + * Stores the current stack pointer and pushes a new frame to the stack. + * + *

This method should be called when entering a method, before doing any stack allocations. When exiting a method, call the {@link #pop} method to + * restore the previous stack frame.

+ * + *

Pairs of push/pop calls may be nested. Care must be taken to:

+ * + * + * @return this stack + */ + public MemoryStack push() { + if (frameIndex == frames.length) { + frameOverflow(); + } + + frames[frameIndex++] = pointer; + return this; + } + + private void frameOverflow() { + if (/*DEBUG*/ false) { + AngelicaTweaker.LOGGER.warn("[WARNING] Out of frame stack space (" + frames.length + ") in thread: " + Thread.currentThread()); + } + frames = Arrays.copyOf(frames, frames.length * 3 / 2); + } + + /** + * Pops the current stack frame and moves the stack pointer to the end of the previous stack frame. + * + * @return this stack + */ + public MemoryStack pop() { + pointer = frames[--frameIndex]; + return this; + } + + /** + * Calls {@link #pop} on this {@code MemoryStack}. + * + *

This method should not be used directly. It is called automatically when the {@code MemoryStack} is used as a resource in a try-with-resources + * statement.

+ */ + @Override + public void close() { + //noinspection resource + pop(); + } + + /** + * Returns the address of the backing off-heap memory. + * + *

The stack grows "downwards", so the bottom of the stack is at {@code address + size}, while the top is at {@code address}.

+ */ + public long getAddress() { + return address; + } + + /** + * Returns the size of the backing off-heap memory. + * + *

This is the maximum number of bytes that may be allocated on the stack.

+ */ + public int getSize() { + return size; + } + + /** + * Returns the current frame index. + * + *

This is the current number of nested {@link #push} calls.

+ */ + public int getFrameIndex() { + return frameIndex; + } + + /** Returns the memory address at the current stack pointer. */ + public long getPointerAddress() { + return address + (pointer & 0xFFFF_FFFFL); + } + + /** + * Returns the current stack pointer. + * + *

The stack grows "downwards", so when the stack is empty {@code pointer} is equal to {@code size}. On every allocation {@code pointer} is reduced by + * the allocated size (after alignment) and {@code address + pointer} points to the first byte of the last allocation.

+ * + *

Effectively, this methods returns how many more bytes may be allocated on the stack.

+ */ + public int getPointer() { + return pointer; + } + + /** + * Sets the current stack pointer. + * + *

This method directly manipulates the stack pointer. Using it irresponsibly may break the internal state of the stack. It should only be used in rare + * cases or in auto-generated code.

+ */ + public void setPointer(int pointer) { + if (/*CHECKS*/ false) { + checkPointer(pointer); + } + + this.pointer = pointer; + } + + private void checkPointer(int pointer) { + if (pointer < 0 || size < pointer) { + throw new IndexOutOfBoundsException("Invalid stack pointer"); + } + } + + private static void checkAlignment(int alignment) { + if (Integer.bitCount(alignment) != 1) { + throw new IllegalArgumentException("Alignment must be a power-of-two value."); + } + } + + /** + * Calls {@link #nmalloc(int, int)} with {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}. + * + * @param size the allocation size + * + * @return the memory address on the stack for the requested allocation + */ + public long nmalloc(int size) { + return nmalloc(POINTER_SIZE, size); + } + + /** + * Allocates a block of {@code size} bytes of memory on the stack. The content of the newly allocated block of memory is not initialized, remaining with + * indeterminate values. + * + * @param alignment the required alignment + * @param size the allocation size + * + * @return the memory address on the stack for the requested allocation + */ + public long nmalloc(int alignment, int size) { + // Align address to the specified alignment + long address = (this.address + pointer - size) & ~Integer.toUnsignedLong(alignment - 1); + + pointer = (int)(address - this.address); + if (/*CHECKS*/ false && pointer < 0) { + throw new OutOfMemoryError("Out of stack space."); + } + + return address; + } + + /** + * Allocates a block of memory on the stack for an array of {@code num} elements, each of them {@code size} bytes long, and initializes all its bits to + * zero. + * + * @param alignment the required element alignment + * @param num num the number of elements to allocate + * @param size the size of each element + * + * @return the memory address on the stack for the requested allocation + */ + public long ncalloc(int alignment, int num, int size) { + int bytes = num * size; + long address = nmalloc(alignment, bytes); + memSet(address, 0, bytes); + return address; + } + + // ------------------------------------------------- + + /** + * Allocates an aligned {@link ByteBuffer} on the stack. + * + * @param alignment the required buffer alignment + * @param size the number of elements in the buffer + * + * @return the allocated buffer + */ + public ByteBuffer malloc(int alignment, int size) { + if (/*DEBUG*/ false) { + checkAlignment(alignment); + } + return MemoryUtil.wrapBufferByte(nmalloc(alignment, size), size); + } + /** Calloc version of {@link #malloc(int, int)}. */ + public ByteBuffer calloc(int alignment, int size) { + if (/*DEBUG*/ false) { + checkAlignment(alignment); + } + return MemoryUtil.wrapBufferByte(ncalloc(alignment, size, 1), size); + } + + /** + * Allocates a {@link ByteBuffer} on the stack with {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}. + * + * @param size the number of elements in the buffer + * + * @return the allocated buffer + */ + public ByteBuffer malloc(int size) { + return MemoryUtil.wrapBufferByte(nmalloc(POINTER_SIZE, size), size); + } + /** Calloc version of {@link #malloc(int)}. */ + public ByteBuffer calloc(int size) { + return MemoryUtil.wrapBufferByte(ncalloc(POINTER_SIZE, size, 1), size); + } + + /** Unsafe version of {@link #bytes(byte)}. */ + public long nbyte(byte value) { + long a = nmalloc(1, 1); + memPutByte(a, value); + return a; + } + /** Single value version of {@link #malloc}. */ + public ByteBuffer bytes(byte x) { return malloc(1, 1).put(0, x); } + /** Two value version of {@link #malloc}. */ + public ByteBuffer bytes(byte x, byte y) { return malloc(1, 2).put(0, x).put(1, y); } + /** Three value version of {@link #malloc}. */ + public ByteBuffer bytes(byte x, byte y, byte z) { return malloc(1, 3).put(0, x).put(1, y).put(2, z); } + /** Four value version of {@link #malloc}. */ + public ByteBuffer bytes(byte x, byte y, byte z, byte w) { return malloc(1, 4).put(0, x).put(1, y).put(2, z).put(3, w); } + /** Vararg version of {@link #malloc}. */ + public ByteBuffer bytes(byte... values) { + ByteBuffer buffer = malloc(1, values.length).put(values); + buffer.flip(); + return buffer; + } + + // ------------------------------------------------- + + /** Short version of {@link #malloc(int)}. */ + public ShortBuffer mallocShort(int size) { return MemoryUtil.wrapBufferShort(nmalloc(2, size << 1), size); } + /** Short version of {@link #calloc(int)}. */ + public ShortBuffer callocShort(int size) { + int bytes = size * 2; + long address = nmalloc(2, bytes); + memSet(address, 0, bytes); + return MemoryUtil.wrapBufferShort(address, size); + } + + /** Unsafe version of {@link #shorts(short)}. */ + public long nshort(short value) { + long a = nmalloc(2, 2); + memPutShort(a, value); + return a; + } + /** Single value version of {@link #mallocShort}. */ + public ShortBuffer shorts(short x) { return mallocShort(1).put(0, x); } + /** Two value version of {@link #mallocShort}. */ + public ShortBuffer shorts(short x, short y) { return mallocShort(2).put(0, x).put(1, y); } + /** Three value version of {@link #mallocShort}. */ + public ShortBuffer shorts(short x, short y, short z) { return mallocShort(3).put(0, x).put(1, y).put(2, z); } + /** Four value version of {@link #mallocShort}. */ + public ShortBuffer shorts(short x, short y, short z, short w) { return mallocShort(4).put(0, x).put(1, y).put(2, z).put(3, w); } + /** Vararg version of {@link #mallocShort}. */ + public ShortBuffer shorts(short... values) { + ShortBuffer buffer = mallocShort(values.length).put(values); + buffer.flip(); + return buffer; + } + + // ------------------------------------------------- + + /** Int version of {@link #malloc(int)}. */ + public IntBuffer mallocInt(int size) { return MemoryUtil.wrapBufferInt(nmalloc(4, size << 2), size); } + /** Int version of {@link #calloc(int)}. */ + public IntBuffer callocInt(int size) { + int bytes = size * 4; + long address = nmalloc(4, bytes); + memSet(address, 0, bytes); + return MemoryUtil.wrapBufferInt(address, size); + } + + /** Unsafe version of {@link #ints(int)}. */ + public long nint(int value) { + long a = nmalloc(4, 4); + memPutInt(a, value); + return a; + } + /** Single value version of {@link #mallocInt}. */ + public IntBuffer ints(int x) { return mallocInt(1).put(0, x); } + /** Two value version of {@link #mallocInt}. */ + public IntBuffer ints(int x, int y) { return mallocInt(2).put(0, x).put(1, y); } + /** Three value version of {@link #mallocInt}. */ + public IntBuffer ints(int x, int y, int z) { return mallocInt(3).put(0, x).put(1, y).put(2, z); } + /** Four value version of {@link #mallocInt}. */ + public IntBuffer ints(int x, int y, int z, int w) { return mallocInt(4).put(0, x).put(1, y).put(2, z).put(3, w); } + /** Vararg version of {@link #mallocInt}. */ + public IntBuffer ints(int... values) { + IntBuffer buffer = mallocInt(values.length).put(values); + buffer.flip(); + return buffer; + } + + // ------------------------------------------------- + + /** Long version of {@link #malloc(int)}. */ + public LongBuffer mallocLong(int size) { return MemoryUtil.wrapBufferLong(nmalloc(8, size << 3), size); } + /** Long version of {@link #calloc(int)}. */ + public LongBuffer callocLong(int size) { + int bytes = size * 8; + long address = nmalloc(8, bytes); + memSet(address, 0, bytes); + return MemoryUtil.wrapBufferLong(address, size); + } + + /** Unsafe version of {@link #longs(long)}. */ + public long nlong(long value) { + long a = nmalloc(8, 8); + memPutLong(a, value); + return a; + } + /** Single value version of {@link #mallocLong}. */ + public LongBuffer longs(long x) { return mallocLong(1).put(0, x); } + /** Two value version of {@link #mallocLong}. */ + public LongBuffer longs(long x, long y) { return mallocLong(2).put(0, x).put(1, y); } + /** Three value version of {@link #mallocLong}. */ + public LongBuffer longs(long x, long y, long z) { return mallocLong(3).put(0, x).put(1, y).put(2, z); } + /** Four value version of {@link #mallocLong}. */ + public LongBuffer longs(long x, long y, long z, long w) { return mallocLong(4).put(0, x).put(1, y).put(2, z).put(3, w); } + /** Vararg version of {@link #mallocLong}. */ + public LongBuffer longs(long... more) { + LongBuffer buffer = mallocLong(more.length).put(more); + buffer.flip(); + return buffer; + } + + // ------------------------------------------------- + + /** CLong version of {@link #malloc(int)}. */ + public CLongBuffer mallocCLong(int size) { return CLongBuffer.create(nmalloc(CLONG_SIZE, size << CLONG_SHIFT), size); } + /** CLong version of {@link #calloc(int)}. */ + public CLongBuffer callocCLong(int size) { + int bytes = size * CLONG_SIZE; + long address = nmalloc(CLONG_SIZE, bytes); + memSet(address, 0, bytes); + return CLongBuffer.create(address, size); + } + + /** Unsafe version of {@link #clongs(long)}. */ + public long nclong(long value) { + long a = nmalloc(CLONG_SIZE, CLONG_SIZE); + memPutCLong(a, value); + return a; + } + /** Single value version of {@link #mallocCLong}. */ + public CLongBuffer clongs(long x) { return mallocCLong(1).put(0, x); } + /** Two value version of {@link #mallocCLong}. */ + public CLongBuffer clongs(long x, long y) { return mallocCLong(2).put(0, x).put(1, y); } + /** Three value version of {@link #mallocCLong}. */ + public CLongBuffer clongs(long x, long y, long z) { return mallocCLong(3).put(0, x).put(1, y).put(2, z); } + /** Four value version of {@link #mallocCLong}. */ + public CLongBuffer clongs(long x, long y, long z, long w) { return mallocCLong(4).put(0, x).put(1, y).put(2, z).put(3, w); } + /** Vararg version of {@link #mallocCLong}. */ + public CLongBuffer clongs(long... values) { + CLongBuffer buffer = mallocCLong(values.length).put(values); + buffer.flip(); + return buffer; + } + + // ------------------------------------------------- + + /** Float version of {@link #malloc(int)}. */ + public FloatBuffer mallocFloat(int size) { return MemoryUtil.wrapBufferFloat(nmalloc(4, size << 2), size); } + /** Float version of {@link #calloc(int)}. */ + public FloatBuffer callocFloat(int size) { + int bytes = size * 4; + long address = nmalloc(4, bytes); + memSet(address, 0, bytes); + return MemoryUtil.wrapBufferFloat(address, size); + } + + /** Unsafe version of {@link #floats(float)}. */ + public long nfloat(float value) { + long a = nmalloc(4, 4); + memPutFloat(a, value); + return a; + } + /** Single value version of {@link #mallocFloat}. */ + public FloatBuffer floats(float x) { return mallocFloat(1).put(0, x); } + /** Two value version of {@link #mallocFloat}. */ + public FloatBuffer floats(float x, float y) { return mallocFloat(2).put(0, x).put(1, y); } + /** Three value version of {@link #mallocFloat}. */ + public FloatBuffer floats(float x, float y, float z) { return mallocFloat(3).put(0, x).put(1, y).put(2, z); } + /** Four value version of {@link #mallocFloat}. */ + public FloatBuffer floats(float x, float y, float z, float w) { return mallocFloat(4).put(0, x).put(1, y).put(2, z).put(3, w); } + /** Vararg version of {@link #mallocFloat}. */ + public FloatBuffer floats(float... values) { + FloatBuffer buffer = mallocFloat(values.length).put(values); + buffer.flip(); + return buffer; + } + + // ------------------------------------------------- + + /** Double version of {@link #malloc(int)}. */ + public DoubleBuffer mallocDouble(int size) { return MemoryUtil.wrapBufferDouble(nmalloc(8, size << 3), size); } + /** Double version of {@link #calloc(int)}. */ + public DoubleBuffer callocDouble(int size) { + int bytes = size * 8; + long address = nmalloc(8, bytes); + memSet(address, 0, bytes); + return MemoryUtil.wrapBufferDouble(address, size); + } + + /** Unsafe version of {@link #doubles(double)}. */ + public long ndouble(double value) { + long a = nmalloc(8, 8); + memPutDouble(a, value); + return a; + } + /** Single value version of {@link #mallocDouble}. */ + public DoubleBuffer doubles(double x) { return mallocDouble(1).put(0, x); } + /** Two value version of {@link #mallocDouble}. */ + public DoubleBuffer doubles(double x, double y) { return mallocDouble(2).put(0, x).put(1, y); } + /** Three value version of {@link #mallocDouble}. */ + public DoubleBuffer doubles(double x, double y, double z) { return mallocDouble(3).put(0, x).put(1, y).put(2, z); } + /** Four value version of {@link #mallocDouble}. */ + public DoubleBuffer doubles(double x, double y, double z, double w) { return mallocDouble(4).put(0, x).put(1, y).put(2, z).put(3, w); } + /** Vararg version of {@link #mallocDouble}. */ + public DoubleBuffer doubles(double... values) { + DoubleBuffer buffer = mallocDouble(values.length).put(values); + buffer.flip(); + return buffer; + } + + // ------------------------------------------------- + + /** Pointer version of {@link #malloc(int)}. */ + public PointerBuffer mallocPointer(int size) { return PointerBuffer.create(nmalloc(POINTER_SIZE, size << POINTER_SHIFT), size); } + /** Pointer version of {@link #calloc(int)}. */ + public PointerBuffer callocPointer(int size) { + int bytes = size * POINTER_SIZE; + long address = nmalloc(POINTER_SIZE, bytes); + memSet(address, 0, bytes); + return PointerBuffer.create(address, size); + } + + /** Unsafe version of {@link #pointers(long)}. */ + public long npointer(long value) { + long a = nmalloc(POINTER_SIZE, POINTER_SIZE); + memPutAddress(a, value); + return a; + } + /** Single value version of {@link #mallocPointer}. */ + public PointerBuffer pointers(long x) { return mallocPointer(1).put(0, x); } + /** Two value version of {@link #mallocPointer}. */ + public PointerBuffer pointers(long x, long y) { return mallocPointer(2).put(0, x).put(1, y); } + /** Three value version of {@link #mallocPointer}. */ + public PointerBuffer pointers(long x, long y, long z) { return mallocPointer(3).put(0, x).put(1, y).put(2, z); } + /** Four value version of {@link #mallocPointer}. */ + public PointerBuffer pointers(long x, long y, long z, long w) { return mallocPointer(4).put(0, x).put(1, y).put(2, z).put(3, w); } + /** Vararg version of {@link #mallocPointer}. */ + public PointerBuffer pointers(long... values) { + PointerBuffer buffer = mallocPointer(values.length).put(values); + buffer.flip(); + return buffer; + } + + /** Unsafe version of {@link #pointers(Pointer)}. */ + public long npointer(Pointer value) { + long a = nmalloc(POINTER_SIZE, POINTER_SIZE); + memPutAddress(a, value.address()); + return a; + } + /** Single value version of {@link #mallocPointer}. */ + public PointerBuffer pointers(Pointer x) { return mallocPointer(1).put(0, x); } + /** Two value version of {@link #mallocPointer}. */ + public PointerBuffer pointers(Pointer x, Pointer y) { return mallocPointer(2).put(0, x).put(1, y); } + /** Three value version of {@link #mallocPointer}. */ + public PointerBuffer pointers(Pointer x, Pointer y, Pointer z) { return mallocPointer(3).put(0, x).put(1, y).put(2, z); } + /** Four value version of {@link #mallocPointer}. */ + public PointerBuffer pointers(Pointer x, Pointer y, Pointer z, Pointer w) { return mallocPointer(4).put(0, x).put(1, y).put(2, z).put(3, w); } + /** Vararg version of {@link #mallocPointer}. */ + public PointerBuffer pointers(Pointer... values) { + PointerBuffer buffer = mallocPointer(values.length); + for (int i = 0; i < values.length; i++) { + buffer.put(i, values[i]); + } + return buffer; + } + + /** Unsafe version of {@link #pointers(Buffer)}. */ + public long npointer(Buffer value) { + long a = nmalloc(POINTER_SIZE, POINTER_SIZE); + memPutAddress(a, memAddress(value)); + return a; + } + /** Single value version of {@link #mallocPointer}. */ + public PointerBuffer pointers(Buffer x) { + return mallocPointer(1) + .put(0, memAddress(x)); + } + /** Two value version of {@link #mallocPointer}. */ + public PointerBuffer pointers(Buffer x, Buffer y) { + return mallocPointer(2) + .put(0, memAddress(x)) + .put(1, memAddress(y)); + } + /** Three value version of {@link #mallocPointer}. */ + public PointerBuffer pointers(Buffer x, Buffer y, Buffer z) { + return mallocPointer(3) + .put(0, memAddress(x)) + .put(1, memAddress(y)) + .put(2, memAddress(z)); + } + /** Four value version of {@link #mallocPointer}. */ + public PointerBuffer pointers(Buffer x, Buffer y, Buffer z, Buffer w) { + return mallocPointer(4) + .put(0, memAddress(x)) + .put(1, memAddress(y)) + .put(2, memAddress(z)) + .put(3, memAddress(w)); + } + /** Vararg version of {@link #mallocPointer}. */ + public PointerBuffer pointers(Buffer... values) { + PointerBuffer buffer = mallocPointer(values.length); + for (int i = 0; i < values.length; i++) { + buffer.put(i, memAddress(values[i])); + } + return buffer; + } + + // ------------------------------------------------- + + /** + * Allocates a new {@link PointerBuffer} of size {@code buffer.remaining()} + * and fills it with the addresses of the values within the provided {@link CustomBuffer} + * starting at {@code buffer.position()}. + * + * @param buffer the {@link CustomBuffer} to obtain its element addresses of + * + * @return a {@link PointerBuffer} containing the buffer's element addresses + */ + public PointerBuffer pointersOfElements(CustomBuffer buffer) { + int remaining = buffer.remaining(); + long addr = buffer.address(); + long sizeof = buffer.sizeof(); + + PointerBuffer pointerBuffer = mallocPointer(remaining); + for (int i = 0; i < remaining; i++) { + pointerBuffer.put(i, addr + sizeof * i); + } + + return pointerBuffer; + } + + // ------------------------------------------------- + + /** + * Encodes the specified text on the stack using ASCII encoding and returns a {@code ByteBuffer} that points to the encoded text, including a + * null-terminator. + * + *

The buffer will have {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}.

+ * + * @param text the text to encode + */ + public ByteBuffer ASCII(CharSequence text) { + return ASCII(text, true); + } + + /** + * Encodes the specified text on the stack using ASCII encoding and returns a {@code ByteBuffer} that points to the encoded text. + * + *

The buffer will have {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}.

+ * + * @param text the text to encode + * @param nullTerminated if true, a null-terminator is included at the end of the encoded text + */ + public ByteBuffer ASCII(CharSequence text, boolean nullTerminated) { + int length = memLengthASCII(text, nullTerminated); + long target = nmalloc(POINTER_SIZE, length); + encodeASCIIUnsafe(text, nullTerminated, target); + return MemoryUtil.wrapBufferByte(target, length); + } + + /** + * Encodes the specified text on the stack using ASCII encoding and returns the encoded text length, in bytes. + * + *

Use {@link #getPointerAddress} immediately after this method to get the encoded text address, which will have {@code alignment} equal to + * {@link Pointer#POINTER_SIZE POINTER_SIZE}.

+ * + * @param text the text to encode + * @param nullTerminated if true, a null-terminator is included at the end of the encoded text + */ + public int nASCII(CharSequence text, boolean nullTerminated) { + long target = nmalloc(POINTER_SIZE, memLengthASCII(text, nullTerminated)); + return encodeASCIIUnsafe(text, nullTerminated, target); + } + + /** Like {@link #ASCII(CharSequence) ASCII}, but returns {@code null} if {@code text} is {@code null}. */ + public @Nullable ByteBuffer ASCIISafe(@Nullable CharSequence text) { + return ASCIISafe(text, true); + } + + /** Like {@link #ASCII(CharSequence, boolean) ASCII}, but returns {@code null} if {@code text} is {@code null}. */ + public @Nullable ByteBuffer ASCIISafe(@Nullable CharSequence text, boolean nullTerminated) { + return text == null ? null : ASCII(text, nullTerminated); + } + + /** Like {@link #nASCII(CharSequence, boolean) nASCII}, but returns 0 if {@code text} is {@code null}. */ + public int nASCIISafe(@Nullable CharSequence text, boolean nullTerminated) { + return text == null ? 0 : nASCII(text, nullTerminated); + } + + /** + * Encodes the specified text on the stack using UTF8 encoding and returns a {@code ByteBuffer} that points to the encoded text, including a + * null-terminator. + * + *

The buffer will have {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}.

+ * + * @param text the text to encode + */ + public ByteBuffer UTF8(CharSequence text) { + return UTF8(text, true); + } + + /** + * Encodes the specified text on the stack using UTF8 encoding and returns a {@code ByteBuffer} that points to the encoded text. + * + *

The buffer will have {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}.

+ * + * @param text the text to encode + * @param nullTerminated if true, a null-terminator is included at the end of the encoded text + */ + public ByteBuffer UTF8(CharSequence text, boolean nullTerminated) { + int length = memLengthUTF8(text, nullTerminated); + long target = nmalloc(POINTER_SIZE, length); + encodeUTF8Unsafe(text, nullTerminated, target); + return MemoryUtil.wrapBufferByte(target, length); + } + + /** + * Encodes the specified text on the stack using UTF8 encoding and returns the encoded text length, in bytes. + * + *

Use {@link #getPointerAddress} immediately after this method to get the encoded text address, which will have {@code alignment} equal to + * {@link Pointer#POINTER_SIZE POINTER_SIZE}.

+ * + * @param text the text to encode + * @param nullTerminated if true, a null-terminator is included at the end of the encoded text + */ + public int nUTF8(CharSequence text, boolean nullTerminated) { + long target = nmalloc(POINTER_SIZE, memLengthUTF8(text, nullTerminated)); + return encodeUTF8Unsafe(text, nullTerminated, target); + } + + /** Like {@link #UTF8(CharSequence) UTF8}, but returns {@code null} if {@code text} is {@code null}. */ + public @Nullable ByteBuffer UTF8Safe(@Nullable CharSequence text) { + return UTF8Safe(text, true); + } + + /** Like {@link #UTF8(CharSequence, boolean) UTF8}, but returns {@code null} if {@code text} is {@code null}. */ + public @Nullable ByteBuffer UTF8Safe(@Nullable CharSequence text, boolean nullTerminated) { + return text == null ? null : UTF8(text, nullTerminated); + } + + /** Like {@link #nUTF8(CharSequence, boolean) nUTF8}, but returns 0 if {@code text} is {@code null}. */ + public int nUTF8Safe(@Nullable CharSequence text, boolean nullTerminated) { + return text == null ? 0 : nUTF8(text, nullTerminated); + } + + /** + * Encodes the specified text on the stack using UTF16 encoding and returns a {@code ByteBuffer} that points to the encoded text, including a + * null-terminator. + * + *

The buffer will have {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}.

+ * + * @param text the text to encode + */ + public ByteBuffer UTF16(CharSequence text) { + return UTF16(text, true); + } + + /** + * Encodes the specified text on the stack using UTF16 encoding and returns a {@code ByteBuffer} that points to the encoded text. + * + *

The buffer will have {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}.

+ * + * @param text the text to encode + * @param nullTerminated if true, a null-terminator is included at the end of the encoded text + */ + public ByteBuffer UTF16(CharSequence text, boolean nullTerminated) { + int length = memLengthUTF16(text, nullTerminated); + long target = nmalloc(POINTER_SIZE, length); + encodeUTF16Unsafe(text, nullTerminated, target); + return MemoryUtil.wrapBufferByte(target, length); + } + + /** + * Encodes the specified text on the stack using UTF16 encoding and returns the encoded text length, in bytes. + * + *

Use {@link #getPointerAddress} immediately after this method to get the encoded text address, which will have {@code alignment} equal to + * {@link Pointer#POINTER_SIZE POINTER_SIZE}.

+ * + * @param text the text to encode + * @param nullTerminated if true, a null-terminator is included at the end of the encoded text + */ + public int nUTF16(CharSequence text, boolean nullTerminated) { + long target = nmalloc(POINTER_SIZE, memLengthUTF16(text, nullTerminated)); + return encodeUTF16Unsafe(text, nullTerminated, target); + } + + /** Like {@link #UTF16(CharSequence) UTF16}, but returns {@code null} if {@code text} is {@code null}. */ + public @Nullable ByteBuffer UTF16Safe(@Nullable CharSequence text) { + return UTF16Safe(text, true); + } + + /** Like {@link #UTF16(CharSequence, boolean) UTF16}, but returns {@code null} if {@code text} is {@code null}. */ + public @Nullable ByteBuffer UTF16Safe(@Nullable CharSequence text, boolean nullTerminated) { + return text == null ? null : UTF16(text, nullTerminated); + } + + /** Like {@link #nUTF16(CharSequence, boolean) nUTF16}, but returns 0 if {@code text} is {@code null}. */ + public int nUTF16Safe(@Nullable CharSequence text, boolean nullTerminated) { + return text == null ? 0 : nUTF16(text, nullTerminated); + } + + // ----------------------------------------------------- + // ----------------------------------------------------- + // ----------------------------------------------------- + + /** Returns the stack of the current thread. */ + public static MemoryStack stackGet() { + return TLS.get(); + } + + /** + * Calls {@link #push} on the stack of the current thread. + * + * @return the stack of the current thread. + */ + public static MemoryStack stackPush() { + return stackGet().push(); + } + + /** + * Calls {@link #pop} on the stack of the current thread. + * + * @return the stack of the current thread. + */ + public static MemoryStack stackPop() { + return stackGet().pop(); + } + + /** Thread-local version of {@link #nmalloc(int)}. */ + public static long nstackMalloc(int size) { return stackGet().nmalloc(size); } + /** Thread-local version of {@link #nmalloc(int, int)}. */ + public static long nstackMalloc(int alignment, int size) { return stackGet().nmalloc(alignment, size); } + /** Thread-local version of {@link #ncalloc}. */ + public static long nstackCalloc(int alignment, int num, int size) { return stackGet().ncalloc(alignment, num, size); } + + // ------------------------------------------------- + + /** Thread-local version of {@link #malloc(int) malloc}. */ + public static ByteBuffer stackMalloc(int size) { return stackGet().malloc(size); } + /** Thread-local version of {@link #calloc(int) calloc}. */ + public static ByteBuffer stackCalloc(int size) { return stackGet().calloc(size); } + + /** Thread-local version of {@link #bytes(byte)}. */ + public static ByteBuffer stackBytes(byte x) { return stackGet().bytes(x); } + /** Thread-local version of {@link #bytes(byte, byte)}. */ + public static ByteBuffer stackBytes(byte x, byte y) { return stackGet().bytes(x, y); } + /** Thread-local version of {@link #bytes(byte, byte, byte)}. */ + public static ByteBuffer stackBytes(byte x, byte y, byte z) { return stackGet().bytes(x, y, z); } + /** Thread-local version of {@link #bytes(byte, byte, byte, byte)}. */ + public static ByteBuffer stackBytes(byte x, byte y, byte z, byte w) { return stackGet().bytes(x, y, z, w); } + /** Thread-local version of {@link #bytes(byte...)}. */ + public static ByteBuffer stackBytes(byte... values) { return stackGet().bytes(values); } + + // ------------------------------------------------- + + /** Thread-local version of {@link #mallocShort}. */ + public static ShortBuffer stackMallocShort(int size) { return stackGet().mallocShort(size); } + /** Thread-local version of {@link #callocShort}. */ + public static ShortBuffer stackCallocShort(int size) { return stackGet().callocShort(size); } + + /** Thread-local version of {@link #shorts(short)}. */ + public static ShortBuffer stackShorts(short x) { return stackGet().shorts(x); } + /** Thread-local version of {@link #shorts(short, short)}. */ + public static ShortBuffer stackShorts(short x, short y) { return stackGet().shorts(x, y); } + /** Thread-local version of {@link #shorts(short, short, short)}. */ + public static ShortBuffer stackShorts(short x, short y, short z) { return stackGet().shorts(x, y, z); } + /** Thread-local version of {@link #shorts(short, short, short, short)}. */ + public static ShortBuffer stackShorts(short x, short y, short z, short w) { return stackGet().shorts(x, y, z, w); } + /** Thread-local version of {@link #shorts(short...)}. */ + public static ShortBuffer stackShorts(short... values) { return stackGet().shorts(values); } + + // ------------------------------------------------- + + /** Thread-local version of {@link #mallocInt}. */ + public static IntBuffer stackMallocInt(int size) { return stackGet().mallocInt(size); } + /** Thread-local version of {@link #callocInt}. */ + public static IntBuffer stackCallocInt(int size) { return stackGet().callocInt(size); } + + /** Thread-local version of {@link #ints(int)}. */ + public static IntBuffer stackInts(int x) { return stackGet().ints(x); } + /** Thread-local version of {@link #ints(int, int)}. */ + public static IntBuffer stackInts(int x, int y) { return stackGet().ints(x, y); } + /** Thread-local version of {@link #ints(int, int, int)}. */ + public static IntBuffer stackInts(int x, int y, int z) { return stackGet().ints(x, y, z); } + /** Thread-local version of {@link #ints(int, int, int, int)}. */ + public static IntBuffer stackInts(int x, int y, int z, int w) { return stackGet().ints(x, y, z, w); } + /** Thread-local version of {@link #ints(int...)}. */ + public static IntBuffer stackInts(int... values) { return stackGet().ints(values); } + + // ------------------------------------------------- + + /** Thread-local version of {@link #mallocLong}. */ + public static LongBuffer stackMallocLong(int size) { return stackGet().mallocLong(size); } + /** Thread-local version of {@link #callocLong}. */ + public static LongBuffer stackCallocLong(int size) { return stackGet().callocLong(size); } + + /** Thread-local version of {@link #longs(long)}. */ + public static LongBuffer stackLongs(long x) { return stackGet().longs(x); } + /** Thread-local version of {@link #longs(long, long)}. */ + public static LongBuffer stackLongs(long x, long y) { return stackGet().longs(x, y); } + /** Thread-local version of {@link #longs(long, long, long)}. */ + public static LongBuffer stackLongs(long x, long y, long z) { return stackGet().longs(x, y, z); } + /** Thread-local version of {@link #longs(long, long, long, long)}. */ + public static LongBuffer stackLongs(long x, long y, long z, long w) { return stackGet().longs(x, y, z, w); } + /** Thread-local version of {@link #longs(long...)}. */ + public static LongBuffer stackLongs(long... values) { return stackGet().longs(values); } + + // ------------------------------------------------- + + /** Thread-local version of {@link #mallocCLong}. */ + public static CLongBuffer stackMallocCLong(int size) { return stackGet().mallocCLong(size); } + /** Thread-local version of {@link #callocCLong}. */ + public static CLongBuffer stackCallocCLong(int size) { return stackGet().callocCLong(size); } + + /** Thread-local version of {@link #longs(long)}. */ + public static CLongBuffer stackCLongs(long x) { return stackGet().clongs(x); } + /** Thread-local version of {@link #longs(long, long)}. */ + public static CLongBuffer stackCLongs(long x, long y) { return stackGet().clongs(x, y); } + /** Thread-local version of {@link #longs(long, long, long)}. */ + public static CLongBuffer stackCLongs(long x, long y, long z) { return stackGet().clongs(x, y, z); } + /** Thread-local version of {@link #longs(long, long, long, long)}. */ + public static CLongBuffer stackCLongs(long x, long y, long z, long w) { return stackGet().clongs(x, y, z, w); } + /** Thread-local version of {@link #longs(long...)}. */ + public static CLongBuffer stackCLongs(long... values) { return stackGet().clongs(values); } + + // ------------------------------------------------- + + /** Thread-local version of {@link #mallocFloat}. */ + public static FloatBuffer stackMallocFloat(int size) { return stackGet().mallocFloat(size); } + /** Thread-local version of {@link #callocFloat}. */ + public static FloatBuffer stackCallocFloat(int size) { return stackGet().callocFloat(size); } + + /** Thread-local version of {@link #floats(float)}. */ + public static FloatBuffer stackFloats(float x) { return stackGet().floats(x); } + /** Thread-local version of {@link #floats(float, float)}. */ + public static FloatBuffer stackFloats(float x, float y) { return stackGet().floats(x, y); } + /** Thread-local version of {@link #floats(float, float, float)}. */ + public static FloatBuffer stackFloats(float x, float y, float z) { return stackGet().floats(x, y, z); } + /** Thread-local version of {@link #floats(float, float, float, float)}. */ + public static FloatBuffer stackFloats(float x, float y, float z, float w) { return stackGet().floats(x, y, z, w); } + /** Thread-local version of {@link #floats(float...)}. */ + public static FloatBuffer stackFloats(float... values) { return stackGet().floats(values); } + + // ------------------------------------------------- + + /** Thread-local version of {@link #mallocDouble}. */ + public static DoubleBuffer stackMallocDouble(int size) { return stackGet().mallocDouble(size); } + /** Thread-local version of {@link #callocDouble}. */ + public static DoubleBuffer stackCallocDouble(int size) { return stackGet().callocDouble(size); } + + /** Thread-local version of {@link #doubles(double)}. */ + public static DoubleBuffer stackDoubles(double x) { return stackGet().doubles(x); } + /** Thread-local version of {@link #doubles(double, double)}. */ + public static DoubleBuffer stackDoubles(double x, double y) { return stackGet().doubles(x, y); } + /** Thread-local version of {@link #doubles(double, double, double)}. */ + public static DoubleBuffer stackDoubles(double x, double y, double z) { return stackGet().doubles(x, y, z); } + /** Thread-local version of {@link #doubles(double, double, double, double)}. */ + public static DoubleBuffer stackDoubles(double x, double y, double z, double w) { return stackGet().doubles(x, y, z, w); } + /** Thread-local version of {@link #doubles(double...)}. */ + public static DoubleBuffer stackDoubles(double... values) { return stackGet().doubles(values); } + + // ------------------------------------------------- + + /** Thread-local version of {@link #mallocPointer}. */ + public static PointerBuffer stackMallocPointer(int size) { return stackGet().mallocPointer(size); } + /** Thread-local version of {@link #callocPointer}. */ + public static PointerBuffer stackCallocPointer(int size) { return stackGet().callocPointer(size); } + + /** Thread-local version of {@link #pointers(long)}. */ + public static PointerBuffer stackPointers(long x) { return stackGet().pointers(x); } + /** Thread-local version of {@link #pointers(long, long)}. */ + public static PointerBuffer stackPointers(long x, long y) { return stackGet().pointers(x, y); } + /** Thread-local version of {@link #pointers(long, long, long)}. */ + public static PointerBuffer stackPointers(long x, long y, long z) { return stackGet().pointers(x, y, z); } + /** Thread-local version of {@link #pointers(long, long, long, long)}. */ + public static PointerBuffer stackPointers(long x, long y, long z, long w) { return stackGet().pointers(x, y, z, w); } + /** Thread-local version of {@link #pointers(long...)}. */ + public static PointerBuffer stackPointers(long... values) { return stackGet().pointers(values); } + + /** Thread-local version of {@link #pointers(Pointer)}. */ + public static PointerBuffer stackPointers(Pointer x) { return stackGet().pointers(x); } + /** Thread-local version of {@link #pointers(Pointer, Pointer)}. */ + public static PointerBuffer stackPointers(Pointer x, Pointer y) { return stackGet().pointers(x, y); } + /** Thread-local version of {@link #pointers(Pointer, Pointer, Pointer)}. */ + public static PointerBuffer stackPointers(Pointer x, Pointer y, Pointer z) { return stackGet().pointers(x, y, z); } + /** Thread-local version of {@link #pointers(Pointer, Pointer, Pointer, Pointer)}. */ + public static PointerBuffer stackPointers(Pointer x, Pointer y, Pointer z, Pointer w) { return stackGet().pointers(x, y, z, w); } + /** Thread-local version of {@link #pointers(Pointer...)}. */ + public static PointerBuffer stackPointers(Pointer... values) { return stackGet().pointers(values); } + + // ------------------------------------------------- + + /** Thread-local version of {@link #ASCII(CharSequence)}. */ + public static ByteBuffer stackASCII(CharSequence text) { return stackGet().ASCII(text); } + + /** Thread-local version of {@link #ASCII(CharSequence, boolean)}. */ + public static ByteBuffer stackASCII(CharSequence text, boolean nullTerminated) { return stackGet().ASCII(text, nullTerminated); } + + /** Thread-local version of {@link #UTF8(CharSequence)}. */ + public static ByteBuffer stackUTF8(CharSequence text) { return stackGet().UTF8(text); } + + /** Thread-local version of {@link #UTF8(CharSequence, boolean)}. */ + public static ByteBuffer stackUTF8(CharSequence text, boolean nullTerminated) { return stackGet().UTF8(text, nullTerminated); } + + /** Thread-local version of {@link #UTF16(CharSequence)}. */ + public static ByteBuffer stackUTF16(CharSequence text) { return stackGet().UTF16(text); } + + /** Thread-local version of {@link #UTF16(CharSequence, boolean)}. */ + public static ByteBuffer stackUTF16(CharSequence text, boolean nullTerminated) { return stackGet().UTF16(text, nullTerminated); } + + /** Thread-local version of {@link #ASCII(CharSequence)}. */ + public static @Nullable ByteBuffer stackASCIISafe(@Nullable CharSequence text) { return stackGet().ASCIISafe(text); } + + /** Thread-local version of {@link #ASCII(CharSequence, boolean)}. */ + public static @Nullable ByteBuffer stackASCIISafe(@Nullable CharSequence text, boolean nullTerminated) { return stackGet().ASCIISafe(text, nullTerminated); } + + /** Thread-local version of {@link #UTF8(CharSequence)}. */ + public static @Nullable ByteBuffer stackUTF8Safe(@Nullable CharSequence text) { return stackGet().UTF8Safe(text); } + + /** Thread-local version of {@link #UTF8(CharSequence, boolean)}. */ + public static @Nullable ByteBuffer stackUTF8Safe(@Nullable CharSequence text, boolean nullTerminated) { return stackGet().UTF8Safe(text, nullTerminated); } + + /** Thread-local version of {@link #UTF16(CharSequence)}. */ + public static @Nullable ByteBuffer stackUTF16Safe(@Nullable CharSequence text) { return stackGet().UTF16Safe(text); } + + /** Thread-local version of {@link #UTF16(CharSequence, boolean)}. */ + public static @Nullable ByteBuffer stackUTF16Safe(@Nullable CharSequence text, boolean nullTerminated) { return stackGet().UTF16Safe(text, nullTerminated); } + +} diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/Pointer.java b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/Pointer.java new file mode 100644 index 000000000..254aabfa8 --- /dev/null +++ b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/Pointer.java @@ -0,0 +1,93 @@ +/* + * This class is backported from LWJGL3 under the BSD 3-clause "New" or "Revised" License + */ +package com.gtnewhorizons.angelica.compat.lwjgl; + + +import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.NULL; +import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.UNSAFE; +import static org.lwjgl.LWJGLUtil.CHECKS; + +import net.minecraft.util.Util; +import org.jetbrains.annotations.Nullable; + +/** + * Pointer interface. + * + *

LWJGL can run on both 32bit and 64bit architectures. Since LWJGL applications deal with native memory directly, this interface provides necessary + * information about the underlying architecture of the running JVM process.

+ * + *

When interacting with native functions, pointer values are mapped to Java {@code long}. LWJGL automatically converts long values to the correct pointer + * addresses when used in native code. Native functions sometimes require arrays of pointer values; the {@link PointerBuffer} class may be used for that + * purpose. It has an API similar to a {@link java.nio.LongBuffer} but handles pointer casts automatically.

+ */ +public interface Pointer { + + /** The pointer size in bytes. Will be 4 on a 32bit JVM and 8 on a 64bit one. */ + int POINTER_SIZE = UNSAFE.addressSize(); + + /** The pointer size power-of-two. Will be 2 on a 32bit JVM and 3 on a 64bit one. */ + int POINTER_SHIFT = POINTER_SIZE == 8 ? 3 : 2; + + /** The value of {@code sizeof(long)} for the current platform. */ + int CLONG_SIZE = POINTER_SIZE == 8 && Util.getOSType() == Util.EnumOS.WINDOWS ? 4 : POINTER_SIZE; + + /** The value of {@code sizeof(long)} as a power-of-two. */ + int CLONG_SHIFT = CLONG_SIZE == 8 ? 3 : 2; + + /** Will be true on a 32bit JVM. */ + boolean BITS32 = POINTER_SIZE * 8 == 32; + + /** Will be true on a 64bit JVM. */ + boolean BITS64 = POINTER_SIZE * 8 == 64; + + /** + * Returns the raw pointer address as a {@code long} value. + * + * @return the pointer address + */ + long address(); + + /** Default {@link Pointer} implementation. */ + abstract class Default implements Pointer { + + // Removed final due to JDK-8139758. TODO: Restore if the fix is backported to JDK 8. + protected long address; + + protected Default(long address) { + if (CHECKS && address == NULL) { + throw new NullPointerException(); + } + this.address = address; + } + + @Override + public long address() { + return address; + } + + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Pointer)) { + return false; + } + + Pointer that = (Pointer)o; + + return address == that.address(); + } + + public int hashCode() { + return (int)(address ^ (address >>> 32)); + } + + @Override + public String toString() { + return String.format("%s pointer [0x%X]", getClass().getSimpleName(), address); + } + + } + +} From 48175cda0b645bdabbafa0fc4933209d50313340 Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Sun, 24 Nov 2024 00:58:46 -0500 Subject: [PATCH 2/8] Remove stubs, for now Will re-add as needed --- .../compat/lwjgl/CompatMemoryUtil.java | 7 + .../angelica/compat/lwjgl/MemoryStack.java | 702 +----------------- 2 files changed, 15 insertions(+), 694 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java index f7b0aac41..ebc7751c5 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java @@ -3,6 +3,7 @@ import static com.gtnewhorizons.angelica.compat.lwjgl.Pointer.BITS64; import static org.lwjgl.MemoryUtil.getAddress; +import java.nio.ByteOrder; import org.lwjgl.BufferUtils; import java.nio.ByteBuffer; @@ -11,6 +12,11 @@ public class CompatMemoryUtil { public static final long NULL = 0; + static final Class BUFFER_BYTE; + static { + ByteBuffer bb = ByteBuffer.allocateDirect(0).order(ByteOrder.nativeOrder()); + BUFFER_BYTE = bb.getClass(); + } public static ByteBuffer memReallocDirect(ByteBuffer old, int capacity) { ByteBuffer newBuf = BufferUtils.createByteBuffer(capacity); @@ -132,6 +138,7 @@ public static void memSet(long ptr, int value, long bytes) { - Unsafe.setMemory is very slow. - A custom Java loop is fastest at small sizes, approximately up to 256 bytes. - The native memset becomes fastest at bigger sizes, when the JNI overhead becomes negligible. + TODO: verify this */ //UNSAFE.setMemory(ptr, bytes, (byte)(value & 0xFF)); diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java index ac6a2b295..591e97223 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java @@ -5,6 +5,13 @@ package com.gtnewhorizons.angelica.compat.lwjgl; +import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memPutDouble; +import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memPutFloat; +import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memPutInt; +import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memPutLong; +import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memPutShort; +import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memSet; + import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import java.nio.ByteBuffer; import java.util.Arrays; @@ -20,6 +27,7 @@ * @ see Configuration#STACK_SIZE * @ see Configuration#DEBUG_STACK */ +@SuppressWarnings("LombokGetterMayBeUsed") public class MemoryStack extends Pointer.Default implements AutoCloseable { private static final int DEFAULT_STACK_SIZE = /*Configuration.STACK_SIZE.get(64)*/ 64 * 1024; @@ -281,556 +289,53 @@ public long ncalloc(int alignment, int num, int size) { // ------------------------------------------------- - /** - * Allocates an aligned {@link ByteBuffer} on the stack. - * - * @param alignment the required buffer alignment - * @param size the number of elements in the buffer - * - * @return the allocated buffer - */ - public ByteBuffer malloc(int alignment, int size) { - if (/*DEBUG*/ false) { - checkAlignment(alignment); - } - return MemoryUtil.wrapBufferByte(nmalloc(alignment, size), size); - } - /** Calloc version of {@link #malloc(int, int)}. */ - public ByteBuffer calloc(int alignment, int size) { - if (/*DEBUG*/ false) { - checkAlignment(alignment); - } - return MemoryUtil.wrapBufferByte(ncalloc(alignment, size, 1), size); - } - - /** - * Allocates a {@link ByteBuffer} on the stack with {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}. - * - * @param size the number of elements in the buffer - * - * @return the allocated buffer - */ - public ByteBuffer malloc(int size) { - return MemoryUtil.wrapBufferByte(nmalloc(POINTER_SIZE, size), size); - } - /** Calloc version of {@link #malloc(int)}. */ - public ByteBuffer calloc(int size) { - return MemoryUtil.wrapBufferByte(ncalloc(POINTER_SIZE, size, 1), size); - } - - /** Unsafe version of {@link #bytes(byte)}. */ - public long nbyte(byte value) { - long a = nmalloc(1, 1); - memPutByte(a, value); - return a; - } - /** Single value version of {@link #malloc}. */ - public ByteBuffer bytes(byte x) { return malloc(1, 1).put(0, x); } - /** Two value version of {@link #malloc}. */ - public ByteBuffer bytes(byte x, byte y) { return malloc(1, 2).put(0, x).put(1, y); } - /** Three value version of {@link #malloc}. */ - public ByteBuffer bytes(byte x, byte y, byte z) { return malloc(1, 3).put(0, x).put(1, y).put(2, z); } - /** Four value version of {@link #malloc}. */ - public ByteBuffer bytes(byte x, byte y, byte z, byte w) { return malloc(1, 4).put(0, x).put(1, y).put(2, z).put(3, w); } - /** Vararg version of {@link #malloc}. */ - public ByteBuffer bytes(byte... values) { - ByteBuffer buffer = malloc(1, values.length).put(values); - buffer.flip(); - return buffer; - } - - // ------------------------------------------------- - - /** Short version of {@link #malloc(int)}. */ - public ShortBuffer mallocShort(int size) { return MemoryUtil.wrapBufferShort(nmalloc(2, size << 1), size); } - /** Short version of {@link #calloc(int)}. */ - public ShortBuffer callocShort(int size) { - int bytes = size * 2; - long address = nmalloc(2, bytes); - memSet(address, 0, bytes); - return MemoryUtil.wrapBufferShort(address, size); - } - /** Unsafe version of {@link #shorts(short)}. */ public long nshort(short value) { long a = nmalloc(2, 2); memPutShort(a, value); return a; } - /** Single value version of {@link #mallocShort}. */ - public ShortBuffer shorts(short x) { return mallocShort(1).put(0, x); } - /** Two value version of {@link #mallocShort}. */ - public ShortBuffer shorts(short x, short y) { return mallocShort(2).put(0, x).put(1, y); } - /** Three value version of {@link #mallocShort}. */ - public ShortBuffer shorts(short x, short y, short z) { return mallocShort(3).put(0, x).put(1, y).put(2, z); } - /** Four value version of {@link #mallocShort}. */ - public ShortBuffer shorts(short x, short y, short z, short w) { return mallocShort(4).put(0, x).put(1, y).put(2, z).put(3, w); } - /** Vararg version of {@link #mallocShort}. */ - public ShortBuffer shorts(short... values) { - ShortBuffer buffer = mallocShort(values.length).put(values); - buffer.flip(); - return buffer; - } // ------------------------------------------------- - /** Int version of {@link #malloc(int)}. */ - public IntBuffer mallocInt(int size) { return MemoryUtil.wrapBufferInt(nmalloc(4, size << 2), size); } - /** Int version of {@link #calloc(int)}. */ - public IntBuffer callocInt(int size) { - int bytes = size * 4; - long address = nmalloc(4, bytes); - memSet(address, 0, bytes); - return MemoryUtil.wrapBufferInt(address, size); - } - /** Unsafe version of {@link #ints(int)}. */ public long nint(int value) { long a = nmalloc(4, 4); memPutInt(a, value); return a; } - /** Single value version of {@link #mallocInt}. */ - public IntBuffer ints(int x) { return mallocInt(1).put(0, x); } - /** Two value version of {@link #mallocInt}. */ - public IntBuffer ints(int x, int y) { return mallocInt(2).put(0, x).put(1, y); } - /** Three value version of {@link #mallocInt}. */ - public IntBuffer ints(int x, int y, int z) { return mallocInt(3).put(0, x).put(1, y).put(2, z); } - /** Four value version of {@link #mallocInt}. */ - public IntBuffer ints(int x, int y, int z, int w) { return mallocInt(4).put(0, x).put(1, y).put(2, z).put(3, w); } - /** Vararg version of {@link #mallocInt}. */ - public IntBuffer ints(int... values) { - IntBuffer buffer = mallocInt(values.length).put(values); - buffer.flip(); - return buffer; - } // ------------------------------------------------- - /** Long version of {@link #malloc(int)}. */ - public LongBuffer mallocLong(int size) { return MemoryUtil.wrapBufferLong(nmalloc(8, size << 3), size); } - /** Long version of {@link #calloc(int)}. */ - public LongBuffer callocLong(int size) { - int bytes = size * 8; - long address = nmalloc(8, bytes); - memSet(address, 0, bytes); - return MemoryUtil.wrapBufferLong(address, size); - } - /** Unsafe version of {@link #longs(long)}. */ public long nlong(long value) { long a = nmalloc(8, 8); memPutLong(a, value); return a; } - /** Single value version of {@link #mallocLong}. */ - public LongBuffer longs(long x) { return mallocLong(1).put(0, x); } - /** Two value version of {@link #mallocLong}. */ - public LongBuffer longs(long x, long y) { return mallocLong(2).put(0, x).put(1, y); } - /** Three value version of {@link #mallocLong}. */ - public LongBuffer longs(long x, long y, long z) { return mallocLong(3).put(0, x).put(1, y).put(2, z); } - /** Four value version of {@link #mallocLong}. */ - public LongBuffer longs(long x, long y, long z, long w) { return mallocLong(4).put(0, x).put(1, y).put(2, z).put(3, w); } - /** Vararg version of {@link #mallocLong}. */ - public LongBuffer longs(long... more) { - LongBuffer buffer = mallocLong(more.length).put(more); - buffer.flip(); - return buffer; - } // ------------------------------------------------- - /** CLong version of {@link #malloc(int)}. */ - public CLongBuffer mallocCLong(int size) { return CLongBuffer.create(nmalloc(CLONG_SIZE, size << CLONG_SHIFT), size); } - /** CLong version of {@link #calloc(int)}. */ - public CLongBuffer callocCLong(int size) { - int bytes = size * CLONG_SIZE; - long address = nmalloc(CLONG_SIZE, bytes); - memSet(address, 0, bytes); - return CLongBuffer.create(address, size); - } - - /** Unsafe version of {@link #clongs(long)}. */ - public long nclong(long value) { - long a = nmalloc(CLONG_SIZE, CLONG_SIZE); - memPutCLong(a, value); - return a; - } - /** Single value version of {@link #mallocCLong}. */ - public CLongBuffer clongs(long x) { return mallocCLong(1).put(0, x); } - /** Two value version of {@link #mallocCLong}. */ - public CLongBuffer clongs(long x, long y) { return mallocCLong(2).put(0, x).put(1, y); } - /** Three value version of {@link #mallocCLong}. */ - public CLongBuffer clongs(long x, long y, long z) { return mallocCLong(3).put(0, x).put(1, y).put(2, z); } - /** Four value version of {@link #mallocCLong}. */ - public CLongBuffer clongs(long x, long y, long z, long w) { return mallocCLong(4).put(0, x).put(1, y).put(2, z).put(3, w); } - /** Vararg version of {@link #mallocCLong}. */ - public CLongBuffer clongs(long... values) { - CLongBuffer buffer = mallocCLong(values.length).put(values); - buffer.flip(); - return buffer; - } - - // ------------------------------------------------- - - /** Float version of {@link #malloc(int)}. */ - public FloatBuffer mallocFloat(int size) { return MemoryUtil.wrapBufferFloat(nmalloc(4, size << 2), size); } - /** Float version of {@link #calloc(int)}. */ - public FloatBuffer callocFloat(int size) { - int bytes = size * 4; - long address = nmalloc(4, bytes); - memSet(address, 0, bytes); - return MemoryUtil.wrapBufferFloat(address, size); - } - /** Unsafe version of {@link #floats(float)}. */ public long nfloat(float value) { long a = nmalloc(4, 4); memPutFloat(a, value); return a; } - /** Single value version of {@link #mallocFloat}. */ - public FloatBuffer floats(float x) { return mallocFloat(1).put(0, x); } - /** Two value version of {@link #mallocFloat}. */ - public FloatBuffer floats(float x, float y) { return mallocFloat(2).put(0, x).put(1, y); } - /** Three value version of {@link #mallocFloat}. */ - public FloatBuffer floats(float x, float y, float z) { return mallocFloat(3).put(0, x).put(1, y).put(2, z); } - /** Four value version of {@link #mallocFloat}. */ - public FloatBuffer floats(float x, float y, float z, float w) { return mallocFloat(4).put(0, x).put(1, y).put(2, z).put(3, w); } - /** Vararg version of {@link #mallocFloat}. */ - public FloatBuffer floats(float... values) { - FloatBuffer buffer = mallocFloat(values.length).put(values); - buffer.flip(); - return buffer; - } // ------------------------------------------------- - /** Double version of {@link #malloc(int)}. */ - public DoubleBuffer mallocDouble(int size) { return MemoryUtil.wrapBufferDouble(nmalloc(8, size << 3), size); } - /** Double version of {@link #calloc(int)}. */ - public DoubleBuffer callocDouble(int size) { - int bytes = size * 8; - long address = nmalloc(8, bytes); - memSet(address, 0, bytes); - return MemoryUtil.wrapBufferDouble(address, size); - } - /** Unsafe version of {@link #doubles(double)}. */ public long ndouble(double value) { long a = nmalloc(8, 8); memPutDouble(a, value); return a; } - /** Single value version of {@link #mallocDouble}. */ - public DoubleBuffer doubles(double x) { return mallocDouble(1).put(0, x); } - /** Two value version of {@link #mallocDouble}. */ - public DoubleBuffer doubles(double x, double y) { return mallocDouble(2).put(0, x).put(1, y); } - /** Three value version of {@link #mallocDouble}. */ - public DoubleBuffer doubles(double x, double y, double z) { return mallocDouble(3).put(0, x).put(1, y).put(2, z); } - /** Four value version of {@link #mallocDouble}. */ - public DoubleBuffer doubles(double x, double y, double z, double w) { return mallocDouble(4).put(0, x).put(1, y).put(2, z).put(3, w); } - /** Vararg version of {@link #mallocDouble}. */ - public DoubleBuffer doubles(double... values) { - DoubleBuffer buffer = mallocDouble(values.length).put(values); - buffer.flip(); - return buffer; - } // ------------------------------------------------- - - /** Pointer version of {@link #malloc(int)}. */ - public PointerBuffer mallocPointer(int size) { return PointerBuffer.create(nmalloc(POINTER_SIZE, size << POINTER_SHIFT), size); } - /** Pointer version of {@link #calloc(int)}. */ - public PointerBuffer callocPointer(int size) { - int bytes = size * POINTER_SIZE; - long address = nmalloc(POINTER_SIZE, bytes); - memSet(address, 0, bytes); - return PointerBuffer.create(address, size); - } - - /** Unsafe version of {@link #pointers(long)}. */ - public long npointer(long value) { - long a = nmalloc(POINTER_SIZE, POINTER_SIZE); - memPutAddress(a, value); - return a; - } - /** Single value version of {@link #mallocPointer}. */ - public PointerBuffer pointers(long x) { return mallocPointer(1).put(0, x); } - /** Two value version of {@link #mallocPointer}. */ - public PointerBuffer pointers(long x, long y) { return mallocPointer(2).put(0, x).put(1, y); } - /** Three value version of {@link #mallocPointer}. */ - public PointerBuffer pointers(long x, long y, long z) { return mallocPointer(3).put(0, x).put(1, y).put(2, z); } - /** Four value version of {@link #mallocPointer}. */ - public PointerBuffer pointers(long x, long y, long z, long w) { return mallocPointer(4).put(0, x).put(1, y).put(2, z).put(3, w); } - /** Vararg version of {@link #mallocPointer}. */ - public PointerBuffer pointers(long... values) { - PointerBuffer buffer = mallocPointer(values.length).put(values); - buffer.flip(); - return buffer; - } - - /** Unsafe version of {@link #pointers(Pointer)}. */ - public long npointer(Pointer value) { - long a = nmalloc(POINTER_SIZE, POINTER_SIZE); - memPutAddress(a, value.address()); - return a; - } - /** Single value version of {@link #mallocPointer}. */ - public PointerBuffer pointers(Pointer x) { return mallocPointer(1).put(0, x); } - /** Two value version of {@link #mallocPointer}. */ - public PointerBuffer pointers(Pointer x, Pointer y) { return mallocPointer(2).put(0, x).put(1, y); } - /** Three value version of {@link #mallocPointer}. */ - public PointerBuffer pointers(Pointer x, Pointer y, Pointer z) { return mallocPointer(3).put(0, x).put(1, y).put(2, z); } - /** Four value version of {@link #mallocPointer}. */ - public PointerBuffer pointers(Pointer x, Pointer y, Pointer z, Pointer w) { return mallocPointer(4).put(0, x).put(1, y).put(2, z).put(3, w); } - /** Vararg version of {@link #mallocPointer}. */ - public PointerBuffer pointers(Pointer... values) { - PointerBuffer buffer = mallocPointer(values.length); - for (int i = 0; i < values.length; i++) { - buffer.put(i, values[i]); - } - return buffer; - } - - /** Unsafe version of {@link #pointers(Buffer)}. */ - public long npointer(Buffer value) { - long a = nmalloc(POINTER_SIZE, POINTER_SIZE); - memPutAddress(a, memAddress(value)); - return a; - } - /** Single value version of {@link #mallocPointer}. */ - public PointerBuffer pointers(Buffer x) { - return mallocPointer(1) - .put(0, memAddress(x)); - } - /** Two value version of {@link #mallocPointer}. */ - public PointerBuffer pointers(Buffer x, Buffer y) { - return mallocPointer(2) - .put(0, memAddress(x)) - .put(1, memAddress(y)); - } - /** Three value version of {@link #mallocPointer}. */ - public PointerBuffer pointers(Buffer x, Buffer y, Buffer z) { - return mallocPointer(3) - .put(0, memAddress(x)) - .put(1, memAddress(y)) - .put(2, memAddress(z)); - } - /** Four value version of {@link #mallocPointer}. */ - public PointerBuffer pointers(Buffer x, Buffer y, Buffer z, Buffer w) { - return mallocPointer(4) - .put(0, memAddress(x)) - .put(1, memAddress(y)) - .put(2, memAddress(z)) - .put(3, memAddress(w)); - } - /** Vararg version of {@link #mallocPointer}. */ - public PointerBuffer pointers(Buffer... values) { - PointerBuffer buffer = mallocPointer(values.length); - for (int i = 0; i < values.length; i++) { - buffer.put(i, memAddress(values[i])); - } - return buffer; - } - // ------------------------------------------------- - - /** - * Allocates a new {@link PointerBuffer} of size {@code buffer.remaining()} - * and fills it with the addresses of the values within the provided {@link CustomBuffer} - * starting at {@code buffer.position()}. - * - * @param buffer the {@link CustomBuffer} to obtain its element addresses of - * - * @return a {@link PointerBuffer} containing the buffer's element addresses - */ - public PointerBuffer pointersOfElements(CustomBuffer buffer) { - int remaining = buffer.remaining(); - long addr = buffer.address(); - long sizeof = buffer.sizeof(); - - PointerBuffer pointerBuffer = mallocPointer(remaining); - for (int i = 0; i < remaining; i++) { - pointerBuffer.put(i, addr + sizeof * i); - } - - return pointerBuffer; - } - // ------------------------------------------------- - /** - * Encodes the specified text on the stack using ASCII encoding and returns a {@code ByteBuffer} that points to the encoded text, including a - * null-terminator. - * - *

The buffer will have {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}.

- * - * @param text the text to encode - */ - public ByteBuffer ASCII(CharSequence text) { - return ASCII(text, true); - } - - /** - * Encodes the specified text on the stack using ASCII encoding and returns a {@code ByteBuffer} that points to the encoded text. - * - *

The buffer will have {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}.

- * - * @param text the text to encode - * @param nullTerminated if true, a null-terminator is included at the end of the encoded text - */ - public ByteBuffer ASCII(CharSequence text, boolean nullTerminated) { - int length = memLengthASCII(text, nullTerminated); - long target = nmalloc(POINTER_SIZE, length); - encodeASCIIUnsafe(text, nullTerminated, target); - return MemoryUtil.wrapBufferByte(target, length); - } - - /** - * Encodes the specified text on the stack using ASCII encoding and returns the encoded text length, in bytes. - * - *

Use {@link #getPointerAddress} immediately after this method to get the encoded text address, which will have {@code alignment} equal to - * {@link Pointer#POINTER_SIZE POINTER_SIZE}.

- * - * @param text the text to encode - * @param nullTerminated if true, a null-terminator is included at the end of the encoded text - */ - public int nASCII(CharSequence text, boolean nullTerminated) { - long target = nmalloc(POINTER_SIZE, memLengthASCII(text, nullTerminated)); - return encodeASCIIUnsafe(text, nullTerminated, target); - } - - /** Like {@link #ASCII(CharSequence) ASCII}, but returns {@code null} if {@code text} is {@code null}. */ - public @Nullable ByteBuffer ASCIISafe(@Nullable CharSequence text) { - return ASCIISafe(text, true); - } - - /** Like {@link #ASCII(CharSequence, boolean) ASCII}, but returns {@code null} if {@code text} is {@code null}. */ - public @Nullable ByteBuffer ASCIISafe(@Nullable CharSequence text, boolean nullTerminated) { - return text == null ? null : ASCII(text, nullTerminated); - } - - /** Like {@link #nASCII(CharSequence, boolean) nASCII}, but returns 0 if {@code text} is {@code null}. */ - public int nASCIISafe(@Nullable CharSequence text, boolean nullTerminated) { - return text == null ? 0 : nASCII(text, nullTerminated); - } - - /** - * Encodes the specified text on the stack using UTF8 encoding and returns a {@code ByteBuffer} that points to the encoded text, including a - * null-terminator. - * - *

The buffer will have {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}.

- * - * @param text the text to encode - */ - public ByteBuffer UTF8(CharSequence text) { - return UTF8(text, true); - } - - /** - * Encodes the specified text on the stack using UTF8 encoding and returns a {@code ByteBuffer} that points to the encoded text. - * - *

The buffer will have {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}.

- * - * @param text the text to encode - * @param nullTerminated if true, a null-terminator is included at the end of the encoded text - */ - public ByteBuffer UTF8(CharSequence text, boolean nullTerminated) { - int length = memLengthUTF8(text, nullTerminated); - long target = nmalloc(POINTER_SIZE, length); - encodeUTF8Unsafe(text, nullTerminated, target); - return MemoryUtil.wrapBufferByte(target, length); - } - - /** - * Encodes the specified text on the stack using UTF8 encoding and returns the encoded text length, in bytes. - * - *

Use {@link #getPointerAddress} immediately after this method to get the encoded text address, which will have {@code alignment} equal to - * {@link Pointer#POINTER_SIZE POINTER_SIZE}.

- * - * @param text the text to encode - * @param nullTerminated if true, a null-terminator is included at the end of the encoded text - */ - public int nUTF8(CharSequence text, boolean nullTerminated) { - long target = nmalloc(POINTER_SIZE, memLengthUTF8(text, nullTerminated)); - return encodeUTF8Unsafe(text, nullTerminated, target); - } - - /** Like {@link #UTF8(CharSequence) UTF8}, but returns {@code null} if {@code text} is {@code null}. */ - public @Nullable ByteBuffer UTF8Safe(@Nullable CharSequence text) { - return UTF8Safe(text, true); - } - - /** Like {@link #UTF8(CharSequence, boolean) UTF8}, but returns {@code null} if {@code text} is {@code null}. */ - public @Nullable ByteBuffer UTF8Safe(@Nullable CharSequence text, boolean nullTerminated) { - return text == null ? null : UTF8(text, nullTerminated); - } - - /** Like {@link #nUTF8(CharSequence, boolean) nUTF8}, but returns 0 if {@code text} is {@code null}. */ - public int nUTF8Safe(@Nullable CharSequence text, boolean nullTerminated) { - return text == null ? 0 : nUTF8(text, nullTerminated); - } - - /** - * Encodes the specified text on the stack using UTF16 encoding and returns a {@code ByteBuffer} that points to the encoded text, including a - * null-terminator. - * - *

The buffer will have {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}.

- * - * @param text the text to encode - */ - public ByteBuffer UTF16(CharSequence text) { - return UTF16(text, true); - } - - /** - * Encodes the specified text on the stack using UTF16 encoding and returns a {@code ByteBuffer} that points to the encoded text. - * - *

The buffer will have {@code alignment} equal to {@link Pointer#POINTER_SIZE POINTER_SIZE}.

- * - * @param text the text to encode - * @param nullTerminated if true, a null-terminator is included at the end of the encoded text - */ - public ByteBuffer UTF16(CharSequence text, boolean nullTerminated) { - int length = memLengthUTF16(text, nullTerminated); - long target = nmalloc(POINTER_SIZE, length); - encodeUTF16Unsafe(text, nullTerminated, target); - return MemoryUtil.wrapBufferByte(target, length); - } - - /** - * Encodes the specified text on the stack using UTF16 encoding and returns the encoded text length, in bytes. - * - *

Use {@link #getPointerAddress} immediately after this method to get the encoded text address, which will have {@code alignment} equal to - * {@link Pointer#POINTER_SIZE POINTER_SIZE}.

- * - * @param text the text to encode - * @param nullTerminated if true, a null-terminator is included at the end of the encoded text - */ - public int nUTF16(CharSequence text, boolean nullTerminated) { - long target = nmalloc(POINTER_SIZE, memLengthUTF16(text, nullTerminated)); - return encodeUTF16Unsafe(text, nullTerminated, target); - } - - /** Like {@link #UTF16(CharSequence) UTF16}, but returns {@code null} if {@code text} is {@code null}. */ - public @Nullable ByteBuffer UTF16Safe(@Nullable CharSequence text) { - return UTF16Safe(text, true); - } - - /** Like {@link #UTF16(CharSequence, boolean) UTF16}, but returns {@code null} if {@code text} is {@code null}. */ - public @Nullable ByteBuffer UTF16Safe(@Nullable CharSequence text, boolean nullTerminated) { - return text == null ? null : UTF16(text, nullTerminated); - } - - /** Like {@link #nUTF16(CharSequence, boolean) nUTF16}, but returns 0 if {@code text} is {@code null}. */ - public int nUTF16Safe(@Nullable CharSequence text, boolean nullTerminated) { - return text == null ? 0 : nUTF16(text, nullTerminated); - } - - // ----------------------------------------------------- - // ----------------------------------------------------- - // ----------------------------------------------------- /** Returns the stack of the current thread. */ public static MemoryStack stackGet() { @@ -864,195 +369,4 @@ public static MemoryStack stackPop() { // ------------------------------------------------- - /** Thread-local version of {@link #malloc(int) malloc}. */ - public static ByteBuffer stackMalloc(int size) { return stackGet().malloc(size); } - /** Thread-local version of {@link #calloc(int) calloc}. */ - public static ByteBuffer stackCalloc(int size) { return stackGet().calloc(size); } - - /** Thread-local version of {@link #bytes(byte)}. */ - public static ByteBuffer stackBytes(byte x) { return stackGet().bytes(x); } - /** Thread-local version of {@link #bytes(byte, byte)}. */ - public static ByteBuffer stackBytes(byte x, byte y) { return stackGet().bytes(x, y); } - /** Thread-local version of {@link #bytes(byte, byte, byte)}. */ - public static ByteBuffer stackBytes(byte x, byte y, byte z) { return stackGet().bytes(x, y, z); } - /** Thread-local version of {@link #bytes(byte, byte, byte, byte)}. */ - public static ByteBuffer stackBytes(byte x, byte y, byte z, byte w) { return stackGet().bytes(x, y, z, w); } - /** Thread-local version of {@link #bytes(byte...)}. */ - public static ByteBuffer stackBytes(byte... values) { return stackGet().bytes(values); } - - // ------------------------------------------------- - - /** Thread-local version of {@link #mallocShort}. */ - public static ShortBuffer stackMallocShort(int size) { return stackGet().mallocShort(size); } - /** Thread-local version of {@link #callocShort}. */ - public static ShortBuffer stackCallocShort(int size) { return stackGet().callocShort(size); } - - /** Thread-local version of {@link #shorts(short)}. */ - public static ShortBuffer stackShorts(short x) { return stackGet().shorts(x); } - /** Thread-local version of {@link #shorts(short, short)}. */ - public static ShortBuffer stackShorts(short x, short y) { return stackGet().shorts(x, y); } - /** Thread-local version of {@link #shorts(short, short, short)}. */ - public static ShortBuffer stackShorts(short x, short y, short z) { return stackGet().shorts(x, y, z); } - /** Thread-local version of {@link #shorts(short, short, short, short)}. */ - public static ShortBuffer stackShorts(short x, short y, short z, short w) { return stackGet().shorts(x, y, z, w); } - /** Thread-local version of {@link #shorts(short...)}. */ - public static ShortBuffer stackShorts(short... values) { return stackGet().shorts(values); } - - // ------------------------------------------------- - - /** Thread-local version of {@link #mallocInt}. */ - public static IntBuffer stackMallocInt(int size) { return stackGet().mallocInt(size); } - /** Thread-local version of {@link #callocInt}. */ - public static IntBuffer stackCallocInt(int size) { return stackGet().callocInt(size); } - - /** Thread-local version of {@link #ints(int)}. */ - public static IntBuffer stackInts(int x) { return stackGet().ints(x); } - /** Thread-local version of {@link #ints(int, int)}. */ - public static IntBuffer stackInts(int x, int y) { return stackGet().ints(x, y); } - /** Thread-local version of {@link #ints(int, int, int)}. */ - public static IntBuffer stackInts(int x, int y, int z) { return stackGet().ints(x, y, z); } - /** Thread-local version of {@link #ints(int, int, int, int)}. */ - public static IntBuffer stackInts(int x, int y, int z, int w) { return stackGet().ints(x, y, z, w); } - /** Thread-local version of {@link #ints(int...)}. */ - public static IntBuffer stackInts(int... values) { return stackGet().ints(values); } - - // ------------------------------------------------- - - /** Thread-local version of {@link #mallocLong}. */ - public static LongBuffer stackMallocLong(int size) { return stackGet().mallocLong(size); } - /** Thread-local version of {@link #callocLong}. */ - public static LongBuffer stackCallocLong(int size) { return stackGet().callocLong(size); } - - /** Thread-local version of {@link #longs(long)}. */ - public static LongBuffer stackLongs(long x) { return stackGet().longs(x); } - /** Thread-local version of {@link #longs(long, long)}. */ - public static LongBuffer stackLongs(long x, long y) { return stackGet().longs(x, y); } - /** Thread-local version of {@link #longs(long, long, long)}. */ - public static LongBuffer stackLongs(long x, long y, long z) { return stackGet().longs(x, y, z); } - /** Thread-local version of {@link #longs(long, long, long, long)}. */ - public static LongBuffer stackLongs(long x, long y, long z, long w) { return stackGet().longs(x, y, z, w); } - /** Thread-local version of {@link #longs(long...)}. */ - public static LongBuffer stackLongs(long... values) { return stackGet().longs(values); } - - // ------------------------------------------------- - - /** Thread-local version of {@link #mallocCLong}. */ - public static CLongBuffer stackMallocCLong(int size) { return stackGet().mallocCLong(size); } - /** Thread-local version of {@link #callocCLong}. */ - public static CLongBuffer stackCallocCLong(int size) { return stackGet().callocCLong(size); } - - /** Thread-local version of {@link #longs(long)}. */ - public static CLongBuffer stackCLongs(long x) { return stackGet().clongs(x); } - /** Thread-local version of {@link #longs(long, long)}. */ - public static CLongBuffer stackCLongs(long x, long y) { return stackGet().clongs(x, y); } - /** Thread-local version of {@link #longs(long, long, long)}. */ - public static CLongBuffer stackCLongs(long x, long y, long z) { return stackGet().clongs(x, y, z); } - /** Thread-local version of {@link #longs(long, long, long, long)}. */ - public static CLongBuffer stackCLongs(long x, long y, long z, long w) { return stackGet().clongs(x, y, z, w); } - /** Thread-local version of {@link #longs(long...)}. */ - public static CLongBuffer stackCLongs(long... values) { return stackGet().clongs(values); } - - // ------------------------------------------------- - - /** Thread-local version of {@link #mallocFloat}. */ - public static FloatBuffer stackMallocFloat(int size) { return stackGet().mallocFloat(size); } - /** Thread-local version of {@link #callocFloat}. */ - public static FloatBuffer stackCallocFloat(int size) { return stackGet().callocFloat(size); } - - /** Thread-local version of {@link #floats(float)}. */ - public static FloatBuffer stackFloats(float x) { return stackGet().floats(x); } - /** Thread-local version of {@link #floats(float, float)}. */ - public static FloatBuffer stackFloats(float x, float y) { return stackGet().floats(x, y); } - /** Thread-local version of {@link #floats(float, float, float)}. */ - public static FloatBuffer stackFloats(float x, float y, float z) { return stackGet().floats(x, y, z); } - /** Thread-local version of {@link #floats(float, float, float, float)}. */ - public static FloatBuffer stackFloats(float x, float y, float z, float w) { return stackGet().floats(x, y, z, w); } - /** Thread-local version of {@link #floats(float...)}. */ - public static FloatBuffer stackFloats(float... values) { return stackGet().floats(values); } - - // ------------------------------------------------- - - /** Thread-local version of {@link #mallocDouble}. */ - public static DoubleBuffer stackMallocDouble(int size) { return stackGet().mallocDouble(size); } - /** Thread-local version of {@link #callocDouble}. */ - public static DoubleBuffer stackCallocDouble(int size) { return stackGet().callocDouble(size); } - - /** Thread-local version of {@link #doubles(double)}. */ - public static DoubleBuffer stackDoubles(double x) { return stackGet().doubles(x); } - /** Thread-local version of {@link #doubles(double, double)}. */ - public static DoubleBuffer stackDoubles(double x, double y) { return stackGet().doubles(x, y); } - /** Thread-local version of {@link #doubles(double, double, double)}. */ - public static DoubleBuffer stackDoubles(double x, double y, double z) { return stackGet().doubles(x, y, z); } - /** Thread-local version of {@link #doubles(double, double, double, double)}. */ - public static DoubleBuffer stackDoubles(double x, double y, double z, double w) { return stackGet().doubles(x, y, z, w); } - /** Thread-local version of {@link #doubles(double...)}. */ - public static DoubleBuffer stackDoubles(double... values) { return stackGet().doubles(values); } - - // ------------------------------------------------- - - /** Thread-local version of {@link #mallocPointer}. */ - public static PointerBuffer stackMallocPointer(int size) { return stackGet().mallocPointer(size); } - /** Thread-local version of {@link #callocPointer}. */ - public static PointerBuffer stackCallocPointer(int size) { return stackGet().callocPointer(size); } - - /** Thread-local version of {@link #pointers(long)}. */ - public static PointerBuffer stackPointers(long x) { return stackGet().pointers(x); } - /** Thread-local version of {@link #pointers(long, long)}. */ - public static PointerBuffer stackPointers(long x, long y) { return stackGet().pointers(x, y); } - /** Thread-local version of {@link #pointers(long, long, long)}. */ - public static PointerBuffer stackPointers(long x, long y, long z) { return stackGet().pointers(x, y, z); } - /** Thread-local version of {@link #pointers(long, long, long, long)}. */ - public static PointerBuffer stackPointers(long x, long y, long z, long w) { return stackGet().pointers(x, y, z, w); } - /** Thread-local version of {@link #pointers(long...)}. */ - public static PointerBuffer stackPointers(long... values) { return stackGet().pointers(values); } - - /** Thread-local version of {@link #pointers(Pointer)}. */ - public static PointerBuffer stackPointers(Pointer x) { return stackGet().pointers(x); } - /** Thread-local version of {@link #pointers(Pointer, Pointer)}. */ - public static PointerBuffer stackPointers(Pointer x, Pointer y) { return stackGet().pointers(x, y); } - /** Thread-local version of {@link #pointers(Pointer, Pointer, Pointer)}. */ - public static PointerBuffer stackPointers(Pointer x, Pointer y, Pointer z) { return stackGet().pointers(x, y, z); } - /** Thread-local version of {@link #pointers(Pointer, Pointer, Pointer, Pointer)}. */ - public static PointerBuffer stackPointers(Pointer x, Pointer y, Pointer z, Pointer w) { return stackGet().pointers(x, y, z, w); } - /** Thread-local version of {@link #pointers(Pointer...)}. */ - public static PointerBuffer stackPointers(Pointer... values) { return stackGet().pointers(values); } - - // ------------------------------------------------- - - /** Thread-local version of {@link #ASCII(CharSequence)}. */ - public static ByteBuffer stackASCII(CharSequence text) { return stackGet().ASCII(text); } - - /** Thread-local version of {@link #ASCII(CharSequence, boolean)}. */ - public static ByteBuffer stackASCII(CharSequence text, boolean nullTerminated) { return stackGet().ASCII(text, nullTerminated); } - - /** Thread-local version of {@link #UTF8(CharSequence)}. */ - public static ByteBuffer stackUTF8(CharSequence text) { return stackGet().UTF8(text); } - - /** Thread-local version of {@link #UTF8(CharSequence, boolean)}. */ - public static ByteBuffer stackUTF8(CharSequence text, boolean nullTerminated) { return stackGet().UTF8(text, nullTerminated); } - - /** Thread-local version of {@link #UTF16(CharSequence)}. */ - public static ByteBuffer stackUTF16(CharSequence text) { return stackGet().UTF16(text); } - - /** Thread-local version of {@link #UTF16(CharSequence, boolean)}. */ - public static ByteBuffer stackUTF16(CharSequence text, boolean nullTerminated) { return stackGet().UTF16(text, nullTerminated); } - - /** Thread-local version of {@link #ASCII(CharSequence)}. */ - public static @Nullable ByteBuffer stackASCIISafe(@Nullable CharSequence text) { return stackGet().ASCIISafe(text); } - - /** Thread-local version of {@link #ASCII(CharSequence, boolean)}. */ - public static @Nullable ByteBuffer stackASCIISafe(@Nullable CharSequence text, boolean nullTerminated) { return stackGet().ASCIISafe(text, nullTerminated); } - - /** Thread-local version of {@link #UTF8(CharSequence)}. */ - public static @Nullable ByteBuffer stackUTF8Safe(@Nullable CharSequence text) { return stackGet().UTF8Safe(text); } - - /** Thread-local version of {@link #UTF8(CharSequence, boolean)}. */ - public static @Nullable ByteBuffer stackUTF8Safe(@Nullable CharSequence text, boolean nullTerminated) { return stackGet().UTF8Safe(text, nullTerminated); } - - /** Thread-local version of {@link #UTF16(CharSequence)}. */ - public static @Nullable ByteBuffer stackUTF16Safe(@Nullable CharSequence text) { return stackGet().UTF16Safe(text); } - - /** Thread-local version of {@link #UTF16(CharSequence, boolean)}. */ - public static @Nullable ByteBuffer stackUTF16Safe(@Nullable CharSequence text, boolean nullTerminated) { return stackGet().UTF16Safe(text, nullTerminated); } - } From c8c5726a6a429644540a20690ca9d350c53f9f4a Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Sun, 24 Nov 2024 21:36:54 -0500 Subject: [PATCH 3/8] Implement mallocInt --- .../compat/lwjgl/CompatMemoryUtil.java | 129 +++++++++++++++++- .../angelica/compat/lwjgl/MemoryStack.java | 5 + 2 files changed, 130 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java index ebc7751c5..9b3ad7541 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java @@ -3,19 +3,38 @@ import static com.gtnewhorizons.angelica.compat.lwjgl.Pointer.BITS64; import static org.lwjgl.MemoryUtil.getAddress; -import java.nio.ByteOrder; -import org.lwjgl.BufferUtils; - +import it.unimi.dsi.fastutil.longs.LongPredicate; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.IntBuffer; +import org.lwjgl.BufferUtils; public class CompatMemoryUtil { public static final long NULL = 0; - static final Class BUFFER_BYTE; + private static final Class BUFFER_BYTE; + private static final Class BUFFER_INT; + + private static final long MARK; + private static final long POSITION; + private static final long LIMIT; + private static final long CAPACITY; + + private static final long ADDRESS; + static { ByteBuffer bb = ByteBuffer.allocateDirect(0).order(ByteOrder.nativeOrder()); BUFFER_BYTE = bb.getClass(); + BUFFER_INT = bb.asIntBuffer().getClass(); + + MARK = getMarkOffset(); + POSITION = getPositionOffset(); + LIMIT = getLimitOffset(); + CAPACITY = getCapacityOffset(); + + ADDRESS = getAddressOffset(); } public static ByteBuffer memReallocDirect(ByteBuffer old, int capacity) { @@ -188,4 +207,106 @@ private static void memSet32(int ptr, int value, int bytes) { UNSAFE.putByte(null, (ptr + i) & 0xFFFF_FFFFL, vb); } } + + /** + * Recursively searches an object and its superclasses for a field with the same name and type. If the field isn't + * public, it may not be stable across library/JVM versions, and these calls are likely not portable. You have been + * warned! + */ + private static long getFieldOffset(Class containerType, Class fieldType, String name) { + Class c = containerType; + while (c != Object.class) { + Field[] fields = c.getDeclaredFields(); + for (Field field : fields) { + if (!field.getType().isAssignableFrom(fieldType) || Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) { + continue; + } + + long offset = UNSAFE.objectFieldOffset(field); + if (field.getName().equals(name)) { + return offset; + } + } + c = c.getSuperclass(); + } + throw new UnsupportedOperationException("Failed to find field offset in class."); + } + + private static long getFieldOffset(Class containerType, Class fieldType, LongPredicate predicate) { + Class c = containerType; + while (c != Object.class) { + Field[] fields = c.getDeclaredFields(); + for (Field field : fields) { + if (!field.getType().isAssignableFrom(fieldType) || Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) { + continue; + } + + long offset = UNSAFE.objectFieldOffset(field); + if (predicate.test(offset)) { + return offset; + } + } + c = c.getSuperclass(); + } + throw new UnsupportedOperationException("Failed to find field offset in class."); + } + + private static long getFieldOffsetInt(Object container, int value) { + return getFieldOffset(container.getClass(), int.class, offset -> UNSAFE.getInt(container, offset) == value); + } + + private static long getAddressOffset() { + final ByteBuffer bb = ByteBuffer.allocateDirect(0); + return getFieldOffset(bb.getClass(), long.class, "address"); + + // TODO: do this portably + // long MAGIC_ADDRESS = 0xDEADBEEF8BADF00DL & (BITS32 ? 0xFFFF_FFFFL : 0xFFFF_FFFF_FFFF_FFFFL); + // ByteBuffer bb = Objects.requireNonNull(NewDirectByteBuffer(MAGIC_ADDRESS, 0)); + //return getFieldOffset(bb.getClass(), long.class, offset -> UNSAFE.getLong(bb, offset) == MAGIC_ADDRESS); + } + + private static final int MAGIC_CAPACITY = 0x0D15EA5E; + private static final int MAGIC_POSITION = 0x00FACADE; + + private static long getMarkOffset() { + // TODO: is this actually reliable without NewDirectByteBuffer? + ByteBuffer bb = ByteBuffer.allocateDirect(0); + return getFieldOffsetInt(bb, -1); + // ByteBuffer bb = Objects.requireNonNull(NewDirectByteBuffer(1L, 0)); + // return getFieldOffsetInt(bb, -1); + } + + private static long getPositionOffset() { + ByteBuffer bb = ByteBuffer.allocateDirect(MAGIC_CAPACITY); + bb.position(MAGIC_POSITION); + return getFieldOffsetInt(bb, MAGIC_POSITION); + } + + private static long getLimitOffset() { + ByteBuffer bb = ByteBuffer.allocateDirect(MAGIC_CAPACITY); + bb.limit(MAGIC_POSITION); + return getFieldOffsetInt(bb, MAGIC_POSITION); + } + + private static long getCapacityOffset() { + ByteBuffer bb = ByteBuffer.allocateDirect(MAGIC_CAPACITY); + bb.limit(0); + return getFieldOffsetInt(bb, MAGIC_CAPACITY); + } + + static IntBuffer wrapBufferInt(long address, int capacity) { + IntBuffer buffer; + try { + buffer = (IntBuffer)UNSAFE.allocateInstance(BUFFER_INT); + } catch (InstantiationException e) { + throw new UnsupportedOperationException(e); + } + + UNSAFE.putLong(buffer, ADDRESS, address); + UNSAFE.putInt(buffer, MARK, -1); + UNSAFE.putInt(buffer, LIMIT, capacity); + UNSAFE.putInt(buffer, CAPACITY, capacity); + + return buffer; + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java index 591e97223..79c6b310b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java @@ -11,9 +11,11 @@ import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memPutLong; import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memPutShort; import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memSet; +import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.wrapBufferInt; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import java.nio.ByteBuffer; +import java.nio.IntBuffer; import java.util.Arrays; import org.jetbrains.annotations.Nullable; import org.lwjgl.BufferUtils; @@ -298,6 +300,9 @@ public long nshort(short value) { // ------------------------------------------------- + /** Int version of {@link #malloc(int)}. */ + public IntBuffer mallocInt(int size) { return wrapBufferInt(nmalloc(4, size << 2), size); } + /** Unsafe version of {@link #ints(int)}. */ public long nint(int value) { long a = nmalloc(4, 4); From 5df10ac0167ae94e903c9005cb1994b455acecc6 Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Sun, 24 Nov 2024 21:49:49 -0500 Subject: [PATCH 4/8] Replace some buffer allocation --- .../angelica/compat/mojang/NativeImage.java | 25 ++++++++++--------- .../angelica/glsm/RenderSystem.java | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java index 03ddd3c51..64d021aa2 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/mojang/NativeImage.java @@ -1,18 +1,17 @@ package com.gtnewhorizons.angelica.compat.mojang; -import lombok.Getter; -import net.coderbot.iris.Iris; -import org.lwjgl.BufferUtils; -import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL12; - -import javax.imageio.ImageIO; +import com.gtnewhorizons.angelica.compat.lwjgl.MemoryStack; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.IntBuffer; +import javax.imageio.ImageIO; +import lombok.Getter; +import net.coderbot.iris.Iris; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; // TBD public class NativeImage extends BufferedImage { @@ -59,12 +58,14 @@ public void downloadTexture(int level, boolean bl) { // final int width = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, level, GL11.GL_TEXTURE_WIDTH); // final int height = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, level, GL11.GL_TEXTURE_HEIGHT); - IntBuffer buffer = BufferUtils.createIntBuffer(size); - int[] data = new int[size]; + try (final MemoryStack stack = MemoryStack.stackPush()) { + final IntBuffer buffer = stack.mallocInt(size); + GL11.glGetTexImage(GL11.GL_TEXTURE_2D, level, format.glFormat, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, buffer); - GL11.glGetTexImage(GL11.GL_TEXTURE_2D, level, format.glFormat, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, buffer); - buffer.get(data); - setRGB(0, 0, width, height, data, 0, width); + int[] data = new int[size]; + buffer.get(data); + setRGB(0, 0, width, height, data, 0, width); + } } public void writeToFile(File file) throws IOException{ try { diff --git a/src/main/java/com/gtnewhorizons/angelica/glsm/RenderSystem.java b/src/main/java/com/gtnewhorizons/angelica/glsm/RenderSystem.java index c7e534dfa..51b97423b 100644 --- a/src/main/java/com/gtnewhorizons/angelica/glsm/RenderSystem.java +++ b/src/main/java/com/gtnewhorizons/angelica/glsm/RenderSystem.java @@ -239,7 +239,7 @@ public static void bindTextureToUnit(int unit, int texture) { dsaState.bindTextureToUnit(unit, texture); } - public static FloatBuffer PROJECTION_MATRIX_BUFFER = BufferUtils.createFloatBuffer(16); + public static final FloatBuffer PROJECTION_MATRIX_BUFFER = BufferUtils.createFloatBuffer(16); public static void setupProjectionMatrix(Matrix4f matrix) { GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glPushMatrix(); From 9890d4bcbb2c82c034e8e7dbc1bea301c37c8f33 Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Sun, 24 Nov 2024 21:54:01 -0500 Subject: [PATCH 5/8] Add mallocFloat --- .../compat/lwjgl/CompatMemoryUtil.java | 18 ++++++++++++++++++ .../angelica/compat/lwjgl/MemoryStack.java | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java index 9b3ad7541..029590c8e 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java @@ -16,6 +16,7 @@ public class CompatMemoryUtil { public static final long NULL = 0; private static final Class BUFFER_BYTE; private static final Class BUFFER_INT; + private static final Class BUFFER_FLOAT; private static final long MARK; private static final long POSITION; @@ -28,6 +29,7 @@ public class CompatMemoryUtil { ByteBuffer bb = ByteBuffer.allocateDirect(0).order(ByteOrder.nativeOrder()); BUFFER_BYTE = bb.getClass(); BUFFER_INT = bb.asIntBuffer().getClass(); + BUFFER_FLOAT = bb.asFloatBuffer().getClass(); MARK = getMarkOffset(); POSITION = getPositionOffset(); @@ -309,4 +311,20 @@ static IntBuffer wrapBufferInt(long address, int capacity) { return buffer; } + + static FloatBuffer wrapBufferFloat(long address, int capacity) { + FloatBuffer buffer; + try { + buffer = (FloatBuffer)UNSAFE.allocateInstance(BUFFER_FLOAT); + } catch (InstantiationException e) { + throw new UnsupportedOperationException(e); + } + + UNSAFE.putLong(buffer, ADDRESS, address); + UNSAFE.putInt(buffer, MARK, -1); + UNSAFE.putInt(buffer, LIMIT, capacity); + UNSAFE.putInt(buffer, CAPACITY, capacity); + + return buffer; + } } diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java index 79c6b310b..28180d803 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/MemoryStack.java @@ -11,10 +11,12 @@ import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memPutLong; import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memPutShort; import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.memSet; +import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.wrapBufferFloat; import static com.gtnewhorizons.angelica.compat.lwjgl.CompatMemoryUtil.wrapBufferInt; import com.gtnewhorizons.angelica.loading.AngelicaTweaker; import java.nio.ByteBuffer; +import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.util.Arrays; import org.jetbrains.annotations.Nullable; @@ -321,6 +323,9 @@ public long nlong(long value) { // ------------------------------------------------- + /** Float version of {@link #malloc(int)}. */ + public FloatBuffer mallocFloat(int size) { return wrapBufferFloat(nmalloc(4, size << 2), size); } + /** Unsafe version of {@link #floats(float)}. */ public long nfloat(float value) { long a = nmalloc(4, 4); From b4b1873f314f8cb9d608f60a6d1e563990ea2399 Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Sun, 24 Nov 2024 22:28:25 -0500 Subject: [PATCH 6/8] Replace more uses of direct buffer allocation --- .../gtnewhorizons/angelica/debug/F3Graph.java | 29 +++++++------ .../iris/gl/framebuffer/GlFramebuffer.java | 41 ++++++++++--------- .../iris/gl/program/ComputeProgram.java | 2 +- .../iris/pipeline/ShadowRenderer.java | 20 ++++----- .../iris/rendertarget/RenderTarget.java | 11 +++-- .../shader_overrides/IrisChunkProgram.java | 13 +++--- 6 files changed, 60 insertions(+), 56 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/debug/F3Graph.java b/src/main/java/com/gtnewhorizons/angelica/debug/F3Graph.java index 7b024b2a3..bb26867ba 100644 --- a/src/main/java/com/gtnewhorizons/angelica/debug/F3Graph.java +++ b/src/main/java/com/gtnewhorizons/angelica/debug/F3Graph.java @@ -30,6 +30,7 @@ import static org.lwjgl.opengl.GL20.glVertexAttribPointer; import com.gtnewhorizon.gtnhlib.client.renderer.shader.ShaderProgram; +import com.gtnewhorizons.angelica.compat.lwjgl.MemoryStack; import java.nio.FloatBuffer; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; @@ -49,7 +50,7 @@ public abstract class F3Graph { private static final int FONT_COLOR = 0xFFE0E0E0; // Due to GLSL 120 limitations, it's just easier to use floats private final FloatBuffer sampleBuf = BufferUtils.createFloatBuffer(NUM_SAMPLES); - private final long[] samples = new long[NUM_SAMPLES]; // CPU-side copy for reads + private final long[] samples = new long[NUM_SAMPLES]; // long version for calculations // Circular buffer holding the last 240 samples, in nanoseconds private int samplesHead = 0; // one ahead of the position of the last sample private boolean initialized = false; @@ -130,18 +131,20 @@ private void init() { // Load vertex buffer vertBuf = glGenBuffers(); glBindBuffer(GL_ARRAY_BUFFER, vertBuf); - final FloatBuffer vertices = BufferUtils.createFloatBuffer(VERT_COUNT * VERT_FLOATS); - // Since we use a triangle strip, we only need 4 vertices. The quad extends to the top of the screen so spikes - // don't get truncated. The max height is replaced in the vert shader, no need to be precise. - vertices.put(new float[]{ - BORDER, BORDER, - WIDTH + BORDER, BORDER, - BORDER, Float.MAX_VALUE, - WIDTH + BORDER, Float.MAX_VALUE - }); - vertices.rewind(); - - glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW); + try (final MemoryStack stack = MemoryStack.stackPush()) { + final FloatBuffer vertices = stack.mallocFloat(VERT_COUNT * VERT_FLOATS); + // Since we use a triangle strip, we only need 4 vertices. The quad extends to the top of the screen so spikes + // don't get truncated. The max height is replaced in the vert shader, no need to be precise. + vertices.put(new float[]{ + BORDER, BORDER, + WIDTH + BORDER, BORDER, + BORDER, Float.MAX_VALUE, + WIDTH + BORDER, Float.MAX_VALUE + }); + vertices.rewind(); + + glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW); + } glBindBuffer(GL_ARRAY_BUFFER, 0); final Minecraft mc = Minecraft.getMinecraft(); diff --git a/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java index a3661f47a..24f314a2d 100644 --- a/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java +++ b/src/main/java/net/coderbot/iris/gl/framebuffer/GlFramebuffer.java @@ -1,19 +1,18 @@ package net.coderbot.iris.gl.framebuffer; +import com.gtnewhorizons.angelica.compat.lwjgl.MemoryStack; import com.gtnewhorizons.angelica.glsm.RenderSystem; import com.gtnewhorizons.angelica.glsm.texture.TextureInfoCache; import it.unimi.dsi.fastutil.ints.Int2IntArrayMap; import it.unimi.dsi.fastutil.ints.Int2IntMap; +import java.nio.IntBuffer; import net.coderbot.iris.gl.GlResource; import net.coderbot.iris.gl.texture.DepthBufferFormat; import net.minecraft.client.renderer.OpenGlHelper; -import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL30; -import java.nio.IntBuffer; - public class GlFramebuffer extends GlResource { private final Int2IntMap attachments; private final int maxDrawBuffers; @@ -52,25 +51,29 @@ public void addColorAttachment(int index, int texture) { } public void noDrawBuffers() { - final IntBuffer buffer = BufferUtils.createIntBuffer(1); - buffer.put(GL11.GL_NONE); - RenderSystem.drawBuffers(getGlId(), buffer); + try (MemoryStack stack = MemoryStack.stackPush()) { + final IntBuffer buffer = stack.mallocInt(1); + buffer.put(GL11.GL_NONE); + RenderSystem.drawBuffers(getGlId(), buffer); + } } public void drawBuffers(int[] buffers) { - final IntBuffer glBuffers = BufferUtils.createIntBuffer(buffers.length); - int index = 0; - - if (buffers.length > maxDrawBuffers) { - throw new IllegalArgumentException("Cannot write to more than " + maxDrawBuffers + " draw buffers on this GPU"); - } - for (int buffer : buffers) { - if (buffer >= maxColorAttachments) { - throw new IllegalArgumentException("Only " + maxColorAttachments + " color attachments are supported on this GPU, but an attempt was made to write to a color attachment with index " + buffer); - } - glBuffers.put(index++, GL30.GL_COLOR_ATTACHMENT0 + buffer); - } - RenderSystem.drawBuffers(getGlId(), glBuffers); + try (MemoryStack stack = MemoryStack.stackPush()) { + final IntBuffer glBuffers = stack.mallocInt(buffers.length); + int index = 0; + + if (buffers.length > maxDrawBuffers) { + throw new IllegalArgumentException("Cannot write to more than " + maxDrawBuffers + " draw buffers on this GPU"); + } + for (int buffer : buffers) { + if (buffer >= maxColorAttachments) { + throw new IllegalArgumentException("Only " + maxColorAttachments + " color attachments are supported on this GPU, but an attempt was made to write to a color attachment with index " + buffer); + } + glBuffers.put(index++, GL30.GL_COLOR_ATTACHMENT0 + buffer); + } + RenderSystem.drawBuffers(getGlId(), glBuffers); + } } public void readBuffer(int buffer) { diff --git a/src/main/java/net/coderbot/iris/gl/program/ComputeProgram.java b/src/main/java/net/coderbot/iris/gl/program/ComputeProgram.java index 570eed35c..a9a3100ec 100644 --- a/src/main/java/net/coderbot/iris/gl/program/ComputeProgram.java +++ b/src/main/java/net/coderbot/iris/gl/program/ComputeProgram.java @@ -19,7 +19,7 @@ public final class ComputeProgram extends GlResource { private Vector3i absoluteWorkGroups; private Vector2f relativeWorkGroups; // private int[] localSize; - private IntBuffer localSizeBuffer; + private final IntBuffer localSizeBuffer; private float cachedWidth; private float cachedHeight; private Vector3i cachedWorkGroups; diff --git a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java index 7218e92ac..798dd603e 100644 --- a/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java +++ b/src/main/java/net/coderbot/iris/pipeline/ShadowRenderer.java @@ -5,12 +5,14 @@ import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.glsm.RenderSystem; -import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt; import com.gtnewhorizons.angelica.rendering.RenderingState; -import cpw.mods.fml.relauncher.ReflectionHelper; -import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; -import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass; import net.coderbot.iris.Iris; import net.coderbot.iris.shaderpack.OptionalBoolean; import net.coderbot.iris.shaderpack.PackDirectives; @@ -33,7 +35,6 @@ import net.minecraft.client.renderer.EntityRenderer; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderGlobal; -import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.culling.Frustrum; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.texture.TextureMap; @@ -52,16 +53,9 @@ import org.lwjgl.opengl.GL14; import org.lwjgl.opengl.GL30; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; - public class ShadowRenderer { public static final Matrix4f MODELVIEW = new Matrix4f(); - public static FloatBuffer MODELVIEW_BUFFER = BufferUtils.createFloatBuffer(16); + public static final FloatBuffer MODELVIEW_BUFFER = BufferUtils.createFloatBuffer(16); public static final Matrix4f PROJECTION = new Matrix4f(); public static List visibleTileEntities; public static boolean ACTIVE = false; diff --git a/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java b/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java index 91993627b..9ca5cb17a 100644 --- a/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java +++ b/src/main/java/net/coderbot/iris/rendertarget/RenderTarget.java @@ -1,5 +1,6 @@ package net.coderbot.iris.rendertarget; +import com.gtnewhorizons.angelica.compat.lwjgl.MemoryStack; import com.gtnewhorizons.angelica.glsm.GLStateManager; import com.gtnewhorizons.angelica.glsm.RenderSystem; import lombok.Getter; @@ -40,11 +41,13 @@ public RenderTarget(Builder builder) { this.width = builder.width; this.height = builder.height; - IntBuffer textures = BufferUtils.createIntBuffer(2); - GL11.glGenTextures(textures); + try (MemoryStack stack = MemoryStack.stackPush()) { + IntBuffer textures = stack.mallocInt(2); + GL11.glGenTextures(textures); - this.mainTexture = textures.get(0); - this.altTexture = textures.get(1); + this.mainTexture = textures.get(0); + this.altTexture = textures.get(1); + } boolean isPixelFormatInteger = builder.internalFormat.getPixelFormat().isInteger(); setupTexture(mainTexture, builder.width, builder.height, !isPixelFormatInteger); diff --git a/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java index 33598af0f..2917a6367 100644 --- a/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java +++ b/src/main/java/net/coderbot/iris/sodium/shader_overrides/IrisChunkProgram.java @@ -1,7 +1,9 @@ package net.coderbot.iris.sodium.shader_overrides; +import com.gtnewhorizons.angelica.compat.lwjgl.MemoryStack; import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import com.gtnewhorizons.angelica.glsm.RenderSystem; +import java.nio.FloatBuffer; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkProgram; import me.jellysquid.mods.sodium.client.render.chunk.shader.ChunkShaderFogComponent; @@ -11,9 +13,6 @@ import net.minecraft.util.ResourceLocation; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; -import org.lwjgl.BufferUtils; - -import java.nio.FloatBuffer; public class IrisChunkProgram extends ChunkProgram { // Uniform variable binding indexes @@ -87,10 +86,12 @@ private void uniformMatrix(int location, Matrix4f matrix) { return; } - FloatBuffer buffer = BufferUtils.createFloatBuffer(16); + try (MemoryStack stack = MemoryStack.stackPush()) { + FloatBuffer buffer = stack.mallocFloat(16); - matrix.get(buffer); + matrix.get(buffer); - RenderSystem.uniformMatrix4fv(location, false, buffer); + RenderSystem.uniformMatrix4fv(location, false, buffer); + } } } From 23904a4809bb0e50bbcdf2db7b47165efe64ee61 Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Sun, 24 Nov 2024 23:23:37 -0500 Subject: [PATCH 7/8] Reorder methods Fixes a clinit crash and makes it easier to compare to upstream --- .../compat/lwjgl/CompatMemoryUtil.java | 167 +++++++++--------- 1 file changed, 82 insertions(+), 85 deletions(-) diff --git a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java index 029590c8e..9d027f736 100644 --- a/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java +++ b/src/main/java/com/gtnewhorizons/angelica/compat/lwjgl/CompatMemoryUtil.java @@ -1,7 +1,6 @@ package com.gtnewhorizons.angelica.compat.lwjgl; import static com.gtnewhorizons.angelica.compat.lwjgl.Pointer.BITS64; -import static org.lwjgl.MemoryUtil.getAddress; import it.unimi.dsi.fastutil.longs.LongPredicate; import java.lang.reflect.Field; @@ -12,8 +11,21 @@ import java.nio.IntBuffer; import org.lwjgl.BufferUtils; +/** + * Backported from LWJGL3 under the BSD 3-Clause "New" or "Revised" License license + * + *

This class provides functionality for managing native memory. + * + *

All methods in this class will make use of {@link sun.misc.Unsafe} if it's available, for performance. If Unsafe is not available, the fallback + * implementations make use of reflection and, in the worst-case, JNI.

+ * + *

Method names in this class are prefixed with {@code mem} to avoid ambiguities when used with static imports.

+ */ public class CompatMemoryUtil { public static final long NULL = 0; + + static final sun.misc.Unsafe UNSAFE; + private static final Class BUFFER_BYTE; private static final Class BUFFER_INT; private static final Class BUFFER_FLOAT; @@ -31,6 +43,8 @@ public class CompatMemoryUtil { BUFFER_INT = bb.asIntBuffer().getClass(); BUFFER_FLOAT = bb.asFloatBuffer().getClass(); + UNSAFE = getUnsafeInstance(); + MARK = getMarkOffset(); POSITION = getPositionOffset(); LIMIT = getLimitOffset(); @@ -66,79 +80,11 @@ public static FloatBuffer memReallocDirect(FloatBuffer old, int capacity) { return newBuf; } - /** - * Backported from LWJGL3 under the BSD 3-Clause "New" or "Revised" License license - * - *

This class provides functionality for managing native memory. - * - *

All methods in this class will make use of {@link sun.misc.Unsafe} if it's available, for performance. If Unsafe is not available, the fallback - * implementations make use of reflection and, in the worst-case, JNI.

- * - *

Method names in this class are prefixed with {@code mem} to avoid ambiguities when used with static imports.

- */ - - static final sun.misc.Unsafe UNSAFE; - - static { - UNSAFE = getUnsafeInstance(); - } - - private static sun.misc.Unsafe getUnsafeInstance() { - java.lang.reflect.Field[] fields = sun.misc.Unsafe.class.getDeclaredFields(); - - /* - Different runtimes use different names for the Unsafe singleton, - so we cannot use .getDeclaredField and we scan instead. For example: - - Oracle: theUnsafe - PERC : m_unsafe_instance - Android: THE_ONE - */ - for (java.lang.reflect.Field field : fields) { - if (!field.getType().equals(sun.misc.Unsafe.class)) { - continue; - } - - int modifiers = field.getModifiers(); - if (!(java.lang.reflect.Modifier.isStatic(modifiers) && java.lang.reflect.Modifier.isFinal(modifiers))) { - continue; - } - - try { - field.setAccessible(true); - return (sun.misc.Unsafe)field.get(null); - } catch (Exception ignored) { - } - break; - } - - throw new UnsupportedOperationException("LWJGL requires sun.misc.Unsafe to be available."); - } - - - public static void memPutByte(long ptr, byte value) { UNSAFE.putByte(null, ptr, value); } - public static void memPutShort(long ptr, short value) { UNSAFE.putShort(null, ptr, value); } - public static void memPutInt(long ptr, int value) { UNSAFE.putInt(null, ptr, value); } - public static void memPutLong(long ptr, long value) { UNSAFE.putLong(null, ptr, value); } - public static void memPutFloat(long ptr, float value) { UNSAFE.putFloat(null, ptr, value); } - public static void memPutDouble(long ptr, double value) { UNSAFE.putDouble(null, ptr, value); } - - public static boolean memGetBoolean(long ptr) { return UNSAFE.getByte(null, ptr) != 0; } - public static byte memGetByte(long ptr) { return UNSAFE.getByte(null, ptr); } - public static short memGetShort(long ptr) { return UNSAFE.getShort(null, ptr); } - public static int memGetInt(long ptr) { return UNSAFE.getInt(null, ptr); } - public static long memGetLong(long ptr) { return UNSAFE.getLong(null, ptr); } - public static float memGetFloat(long ptr) { return UNSAFE.getFloat(null, ptr); } - public static double memGetDouble(long ptr) { return UNSAFE.getDouble(null, ptr); } - - /** - * Sets all bytes in a specified block of memory to a fixed value (usually zero). - * - * @param ptr the starting memory address - * @param value the value to set (memSet will convert it to unsigned byte) - */ - public static void memSet(ByteBuffer ptr, int value) { memSet(getAddress(ptr), value, ptr.remaining()); } - + /* ------------------------------------- + ------------------------------------- + UNSAFE MEMORY ACCESS API + ------------------------------------- + ------------------------------------- */ private static final int FILL_PATTERN_32 = Integer.divideUnsigned(-1, 255); private static final long FILL_PATTERN_64 = Long.divideUnsigned(-1L, 255L); @@ -164,18 +110,18 @@ public static void memSet(long ptr, int value, long bytes) { //UNSAFE.setMemory(ptr, bytes, (byte)(value & 0xFF)); //if (bytes < 256L) { - int p = (int)ptr; - if (BITS64) { - if ((p & 7) == 0) { - memSet64(ptr, value, (int)bytes & 0xFF); - return; - } - } else { - if ((p & 3) == 0) { - memSet32(p, value, (int)bytes & 0xFF); - return; - } + int p = (int)ptr; + if (BITS64) { + if ((p & 7) == 0) { + memSet64(ptr, value, (int)bytes & 0xFF); + return; } + } else { + if ((p & 3) == 0) { + memSet32(p, value, (int)bytes & 0xFF); + return; + } + } //} //nmemset(ptr, value, bytes); } @@ -210,6 +156,57 @@ private static void memSet32(int ptr, int value, int bytes) { } } + public static boolean memGetBoolean(long ptr) { return UNSAFE.getByte(null, ptr) != 0; } + public static byte memGetByte(long ptr) { return UNSAFE.getByte(null, ptr); } + public static short memGetShort(long ptr) { return UNSAFE.getShort(null, ptr); } + public static int memGetInt(long ptr) { return UNSAFE.getInt(null, ptr); } + public static long memGetLong(long ptr) { return UNSAFE.getLong(null, ptr); } + public static float memGetFloat(long ptr) { return UNSAFE.getFloat(null, ptr); } + public static double memGetDouble(long ptr) { return UNSAFE.getDouble(null, ptr); } + + public static void memPutByte(long ptr, byte value) { UNSAFE.putByte(null, ptr, value); } + public static void memPutShort(long ptr, short value) { UNSAFE.putShort(null, ptr, value); } + public static void memPutInt(long ptr, int value) { UNSAFE.putInt(null, ptr, value); } + public static void memPutLong(long ptr, long value) { UNSAFE.putLong(null, ptr, value); } + public static void memPutFloat(long ptr, float value) { UNSAFE.putFloat(null, ptr, value); } + public static void memPutDouble(long ptr, double value) { UNSAFE.putDouble(null, ptr, value); } + + // ------------------------------------------------- + // ------------------------------------------------- + // ------------------------------------------------- + + private static sun.misc.Unsafe getUnsafeInstance() { + java.lang.reflect.Field[] fields = sun.misc.Unsafe.class.getDeclaredFields(); + + /* + Different runtimes use different names for the Unsafe singleton, + so we cannot use .getDeclaredField and we scan instead. For example: + + Oracle: theUnsafe + PERC : m_unsafe_instance + Android: THE_ONE + */ + for (java.lang.reflect.Field field : fields) { + if (!field.getType().equals(sun.misc.Unsafe.class)) { + continue; + } + + int modifiers = field.getModifiers(); + if (!(java.lang.reflect.Modifier.isStatic(modifiers) && java.lang.reflect.Modifier.isFinal(modifiers))) { + continue; + } + + try { + field.setAccessible(true); + return (sun.misc.Unsafe)field.get(null); + } catch (Exception ignored) { + } + break; + } + + throw new UnsupportedOperationException("LWJGL requires sun.misc.Unsafe to be available."); + } + /** * Recursively searches an object and its superclasses for a field with the same name and type. If the field isn't * public, it may not be stable across library/JVM versions, and these calls are likely not portable. You have been From 6b045bc12197d417021775c3b58aab79a3ae03a8 Mon Sep 17 00:00:00 2001 From: ah-OOG-ah <75745146+ah-OOG-ah@users.noreply.github.com> Date: Sun, 24 Nov 2024 23:41:01 -0500 Subject: [PATCH 8/8] Remove another direct buffer creation --- .../mods/sodium/client/render/GameRendererContext.java | 9 ++++----- .../sodium/client/render/chunk/shader/ChunkProgram.java | 9 ++++++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java index 65535adf1..3d65f43cd 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/GameRendererContext.java @@ -1,13 +1,12 @@ package me.jellysquid.mods.sodium.client.render; +import com.gtnewhorizons.angelica.compat.lwjgl.MemoryStack; import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import com.gtnewhorizons.angelica.config.AngelicaConfig; import com.gtnewhorizons.angelica.rendering.RenderingState; +import java.nio.FloatBuffer; import net.coderbot.iris.shadows.ShadowRenderingState; import org.joml.Matrix4f; -import org.lwjgl.BufferUtils; - -import java.nio.FloatBuffer; public class GameRendererContext { /** @@ -17,8 +16,8 @@ public class GameRendererContext { * @return A float-buffer on the stack containing the model-view-projection matrix in a format suitable for * uploading as uniform state */ - public static FloatBuffer getModelViewProjectionMatrix(MatrixStack.Entry matrices) { - final FloatBuffer bufModelViewProjection = BufferUtils.createFloatBuffer(16); + public static FloatBuffer getModelViewProjectionMatrix(MatrixStack.Entry matrices, MemoryStack stack) { + final FloatBuffer bufModelViewProjection = stack.mallocFloat(16); final Matrix4f projectionMatrix = (AngelicaConfig.enableIris && ShadowRenderingState.areShadowsCurrentlyBeingRendered()) ? ShadowRenderingState.getShadowOrthoMatrix() : RenderingState.INSTANCE.getProjectionMatrix(); final Matrix4f matrix = new Matrix4f(projectionMatrix); matrix.mul(matrices.getModel()); diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java index f2e05b687..6d26d4fa5 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/shader/ChunkProgram.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.render.chunk.shader; +import com.gtnewhorizons.angelica.compat.lwjgl.MemoryStack; import com.gtnewhorizons.angelica.compat.toremove.MatrixStack; import me.jellysquid.mods.sodium.client.gl.device.RenderDevice; import me.jellysquid.mods.sodium.client.gl.shader.GlProgram; @@ -47,6 +48,12 @@ public void setup(MatrixStack matrixStack, float modelScale, float textureScale) this.fogShader.setup(); - if(this.uModelViewProjectionMatrix != -1) GL20.glUniformMatrix4(this.uModelViewProjectionMatrix, false, GameRendererContext.getModelViewProjectionMatrix(matrixStack.peek())); + if (this.uModelViewProjectionMatrix == -1) return; + try (MemoryStack stack = MemoryStack.stackPush()) { + GL20.glUniformMatrix4( + this.uModelViewProjectionMatrix, + false, + GameRendererContext.getModelViewProjectionMatrix(matrixStack.peek(), stack)); + } } }