diff --git a/src/main/java/com/jozufozu/flywheel/api/material/Material.java b/src/main/java/com/jozufozu/flywheel/api/material/Material.java index a93091d89..dc0db130f 100644 --- a/src/main/java/com/jozufozu/flywheel/api/material/Material.java +++ b/src/main/java/com/jozufozu/flywheel/api/material/Material.java @@ -22,7 +22,7 @@ public interface Material { VertexTransformer getVertexTransformer(); - public interface VertexTransformer { + interface VertexTransformer { void transform(MutableVertexList vertexList, ClientLevel level); } } diff --git a/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java b/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java index ba6922888..0c35a7124 100644 --- a/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java +++ b/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java @@ -1,7 +1,5 @@ package com.jozufozu.flywheel.api.struct; -import java.nio.ByteBuffer; - import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.vertex.MutableVertexList; import com.jozufozu.flywheel.core.layout.BufferLayout; @@ -25,22 +23,17 @@ public interface StructType { */ BufferLayout getLayout(); - /** - * Create a {@link StructWriter} that will consume instances of S and write them to the given buffer. - * - * @param backing The buffer that the StructWriter will write to. - */ - StructWriter getWriter(ByteBuffer backing); + StructWriter getWriter(); FileResolution getInstanceShader(); - VertexTransformer getVertexTransformer(); + VertexTransformer getVertexTransformer(); StorageBufferWriter getStorageBufferWriter(); FileResolution getIndirectShader(); - public interface VertexTransformer { + interface VertexTransformer { void transform(MutableVertexList vertexList, S struct, ClientLevel level); } diff --git a/src/main/java/com/jozufozu/flywheel/api/struct/StructWriter.java b/src/main/java/com/jozufozu/flywheel/api/struct/StructWriter.java index abebee807..5b1e0bd33 100644 --- a/src/main/java/com/jozufozu/flywheel/api/struct/StructWriter.java +++ b/src/main/java/com/jozufozu/flywheel/api/struct/StructWriter.java @@ -1,17 +1,13 @@ package com.jozufozu.flywheel.api.struct; +import com.jozufozu.flywheel.api.instancer.InstancedPart; + /** - * StructWriters can quickly consume many instances of S and write them to some backing buffer. + * StructWriters can quickly consume many instances of S and write them to some memory address. */ -public interface StructWriter { - +public interface StructWriter { /** - * Write the given struct to the backing array. + * Write the given struct to the given memory address. */ - void write(S struct); - - /** - * Seek to the given position. The next write will occur there. - */ - void seek(int pos); + void write(long ptr, S struct); } diff --git a/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java b/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java index b23639183..06716f2bc 100644 --- a/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java +++ b/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java @@ -1,18 +1,16 @@ package com.jozufozu.flywheel.api.uniform; -import java.nio.ByteBuffer; - import com.jozufozu.flywheel.core.source.FileResolution; public abstract class UniformProvider { - protected ByteBuffer buffer; + protected long ptr; protected Notifier notifier; public abstract int getActualByteSize(); - public void updatePtr(ByteBuffer backing, Notifier notifier) { - this.buffer = backing; + public void updatePtr(long ptr, Notifier notifier) { + this.ptr = ptr; this.notifier = notifier; } diff --git a/src/main/java/com/jozufozu/flywheel/api/vertex/ReusableVertexList.java b/src/main/java/com/jozufozu/flywheel/api/vertex/ReusableVertexList.java new file mode 100644 index 000000000..c4f9c4b70 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/vertex/ReusableVertexList.java @@ -0,0 +1,11 @@ +package com.jozufozu.flywheel.api.vertex; + +public interface ReusableVertexList extends MutableVertexList { + long ptr(); + + void ptr(long ptr); + + void shiftPtr(int vertices); + + void setVertexCount(int vertexCount); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexList.java b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexList.java index cf9d84789..b8edf82a9 100644 --- a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexList.java +++ b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexList.java @@ -44,6 +44,37 @@ public interface VertexList extends PointSet { float normalZ(int index); + default void write(MutableVertexList dst, int srcIndex, int dstIndex) { + dst.x(dstIndex, x(srcIndex)); + dst.y(dstIndex, y(srcIndex)); + dst.z(dstIndex, z(srcIndex)); + + dst.r(dstIndex, r(srcIndex)); + dst.g(dstIndex, g(srcIndex)); + dst.b(dstIndex, b(srcIndex)); + dst.a(dstIndex, a(srcIndex)); + + dst.u(dstIndex, u(srcIndex)); + dst.v(dstIndex, v(srcIndex)); + + dst.overlay(dstIndex, overlay(srcIndex)); + dst.light(dstIndex, light(srcIndex)); + + dst.normalX(dstIndex, normalX(srcIndex)); + dst.normalY(dstIndex, normalY(srcIndex)); + dst.normalZ(dstIndex, normalZ(srcIndex)); + } + + default void write(MutableVertexList dst, int srcStartIndex, int dstStartIndex, int vertexCount) { + for (int i = 0; i < vertexCount; i++) { + write(dst, srcStartIndex + i, dstStartIndex + i); + } + } + + default void writeAll(MutableVertexList dst) { + write(dst, 0, 0, getVertexCount()); + } + int getVertexCount(); default boolean isEmpty() { diff --git a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexListProvider.java b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexListProvider.java new file mode 100644 index 000000000..a200e03ad --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexListProvider.java @@ -0,0 +1,5 @@ +package com.jozufozu.flywheel.api.vertex; + +public interface VertexListProvider { + ReusableVertexList createVertexList(); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexType.java b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexType.java index 1ae89d406..72dab420d 100644 --- a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexType.java +++ b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexType.java @@ -1,38 +1,18 @@ package com.jozufozu.flywheel.api.vertex; -import java.nio.ByteBuffer; - import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.source.FileResolution; /** * A vertex type containing metadata about a specific vertex layout. */ -public interface VertexType { +public interface VertexType extends VertexListProvider { /** * The layout of this type of vertex when buffered. */ BufferLayout getLayout(); - /** - * Create a writer backed by the given ByteBuffer. - * - *

- * Implementors are encouraged to override the return type for ergonomics. - *

- */ - VertexWriter createWriter(ByteBuffer buffer); - - /** - * Create a view of the given ByteBuffer as if it were already filled with vertices. - * - *

- * Implementors are encouraged to override the return type for ergonomics. - *

- */ - VertexList createReader(ByteBuffer buffer, int vertexCount); - FileResolution getLayoutShader(); default int getStride() { diff --git a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexWriter.java b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexWriter.java deleted file mode 100644 index a16f0eec5..000000000 --- a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexWriter.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.jozufozu.flywheel.api.vertex; - -public interface VertexWriter { - void writeVertex(VertexList list, int index); - - void seek(long offset); - - VertexList intoReader(int vertices); - - default void writeVertexList(VertexList list) { - for (int i = 0; i < list.getVertexCount(); i++) { - this.writeVertex(list, i); - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/FlywheelMemory.java b/src/main/java/com/jozufozu/flywheel/backend/FlywheelMemory.java deleted file mode 100644 index 3d3f8bd60..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/FlywheelMemory.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.jozufozu.flywheel.backend; - -import java.lang.ref.Cleaner; -import java.nio.ByteBuffer; - -import org.lwjgl.system.MemoryUtil; - -public class FlywheelMemory { - - public static final Cleaner CLEANER = Cleaner.create(); - - private static int gpuMemory = 0; - private static int cpuMemory = 0; - - public static void _freeCPUMemory(long size) { - cpuMemory -= size; - } - - public static void _allocCPUMemory(long size) { - cpuMemory += size; - } - - public static void _freeGPUMemory(long size) { - gpuMemory -= size; - } - - public static void _allocGPUMemory(long size) { - gpuMemory += size; - } - - public static int getGPUMemory() { - return gpuMemory; - } - - public static int getCPUMemory() { - return cpuMemory; - } - - public static Cleaner.Cleanable track(Object owner, ByteBuffer buffer) { - return CLEANER.register(owner, new Tracked(buffer)); - } - - public static class Tracked implements Runnable { - - private final ByteBuffer buffer; - - public Tracked(ByteBuffer buffer) { - this.buffer = buffer; - _allocCPUMemory(buffer.capacity()); - } - - public void run() { - _freeCPUMemory(buffer.capacity()); - MemoryUtil.memFree(buffer); - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java index 395c514ec..ef8eaa6df 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java @@ -1,49 +1,111 @@ package com.jozufozu.flywheel.backend.gl.buffer; -import java.nio.ByteBuffer; +import static org.lwjgl.opengl.GL15.glBufferData; +import static org.lwjgl.opengl.GL15.glDeleteBuffers; +import static org.lwjgl.opengl.GL15.glGenBuffers; +import static org.lwjgl.opengl.GL15.nglBufferData; +import static org.lwjgl.opengl.GL30.GL_MAP_WRITE_BIT; +import static org.lwjgl.opengl.GL30.nglMapBufferRange; +import static org.lwjgl.opengl.GL31.glCopyBufferSubData; -import org.lwjgl.opengl.GL20; +import org.lwjgl.system.MemoryUtil; import com.jozufozu.flywheel.backend.gl.GlObject; -import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; +import com.jozufozu.flywheel.backend.gl.error.GlError; +import com.jozufozu.flywheel.backend.gl.error.GlException; +import com.jozufozu.flywheel.backend.memory.FlwMemoryTracker; +import com.jozufozu.flywheel.backend.memory.MemoryBlock; -public abstract class GlBuffer extends GlObject { - - /** - * Request a Persistent mapped buffer. - * - *

- * If Persistent buffers are supported, this will provide one. Otherwise it will fall back to a classic mapped - * buffer. - *

- * - * @param type The type of buffer you want. - * @return A buffer that will be persistent if the driver supports it. - */ - public static GlBuffer requestPersistent(GlBufferType type) { - if (GlCompat.getInstance() - .bufferStorageSupported()) { - return new PersistentGlBuffer(type); - } else { - return new MappedGlBuffer(type); - } - } +public class GlBuffer extends GlObject { public final GlBufferType type; - + protected final GlBufferUsage usage; /** * The size (in bytes) of the buffer on the GPU. */ protected long size; - /** * How much extra room to give the buffer when we reallocate. */ protected int growthMargin; public GlBuffer(GlBufferType type) { - setHandle(GL20.glGenBuffers()); + this(type, GlBufferUsage.STATIC_DRAW); + } + + public GlBuffer(GlBufferType type, GlBufferUsage usage) { + setHandle(glGenBuffers()); this.type = type; + this.usage = usage; + } + + public boolean ensureCapacity(long size) { + if (size < 0) { + throw new IllegalArgumentException("Size " + size + " < 0"); + } + + if (size == 0) { + return false; + } + + if (this.size == 0) { + this.size = size; + bind(); + glBufferData(type.glEnum, size, usage.glEnum); + FlwMemoryTracker._allocGPUMemory(size); + + return true; + } + + if (size > this.size) { + var oldSize = this.size; + this.size = size + growthMargin; + + realloc(oldSize, this.size); + + return true; + } + + return false; + } + + private void realloc(long oldSize, long newSize) { + FlwMemoryTracker._freeGPUMemory(oldSize); + FlwMemoryTracker._allocGPUMemory(newSize); + var oldHandle = handle(); + var newHandle = glGenBuffers(); + + GlBufferType.COPY_READ_BUFFER.bind(oldHandle); + type.bind(newHandle); + + glBufferData(type.glEnum, newSize, usage.glEnum); + glCopyBufferSubData(GlBufferType.COPY_READ_BUFFER.glEnum, type.glEnum, 0, 0, oldSize); + + glDeleteBuffers(oldHandle); + setHandle(newHandle); + } + + public void upload(MemoryBlock directBuffer) { + bind(); + FlwMemoryTracker._freeGPUMemory(size); + nglBufferData(type.glEnum, directBuffer.size(), directBuffer.ptr(), usage.glEnum); + this.size = directBuffer.size(); + FlwMemoryTracker._allocGPUMemory(size); + } + + public MappedBuffer map() { + bind(); + long ptr = nglMapBufferRange(type.glEnum, 0, size, GL_MAP_WRITE_BIT); + + if (ptr == MemoryUtil.NULL) { + throw new GlException(GlError.poll(), "Could not map buffer"); + } + + return new MappedBuffer(this, ptr, 0, size); + } + + public boolean isPersistent() { + return false; } public void setGrowthMargin(int growthMargin) { @@ -66,24 +128,8 @@ public abstract class GlBuffer extends GlObject { type.unbind(); } - public abstract void upload(ByteBuffer directBuffer); - - public abstract MappedBuffer map(); - - /** - * Ensure that the buffer has at least enough room to store {@code size} bytes. - * - * @return {@code true} if the buffer moved. - */ - public abstract boolean ensureCapacity(long size); - protected void deleteInternal(int handle) { - GL20.glDeleteBuffers(handle); + glDeleteBuffers(handle); + FlwMemoryTracker._freeGPUMemory(size); } - - /** - * Indicates that this buffer need not be #flush()'d for its contents to sync. - * @return true if this buffer is persistently mapped. - */ - public abstract boolean isPersistent(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedBuffer.java index 4ccdbe721..4b2da8992 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedBuffer.java @@ -1,6 +1,6 @@ package com.jozufozu.flywheel.backend.gl.buffer; -import java.nio.ByteBuffer; +import static org.lwjgl.system.MemoryUtil.NULL; import org.lwjgl.opengl.GL15; import org.lwjgl.system.MemoryUtil; @@ -11,10 +11,10 @@ public class MappedBuffer implements AutoCloseable { private final long length; private final GlBuffer owner; private final boolean persistent; - private ByteBuffer internal; + private long ptr; - public MappedBuffer(GlBuffer owner, ByteBuffer internal, long offset, long length) { - this.internal = internal; + public MappedBuffer(GlBuffer owner, long ptr, long offset, long length) { + this.ptr = ptr; this.owner = owner; this.offset = offset; this.length = length; @@ -27,19 +27,11 @@ public class MappedBuffer implements AutoCloseable { public void flush() { if (persistent) return; - if (internal == null) return; + if (ptr == NULL) return; owner.bind(); GL15.glUnmapBuffer(owner.getType().glEnum); - internal = null; - } - - public MappedBuffer position(int p) { - if (p < offset || p >= offset + length) { - throw new IndexOutOfBoundsException("Index " + p + " is not mapped"); - } - internal.position(p - (int) offset); - return this; + ptr = NULL; } @Override @@ -47,12 +39,8 @@ public class MappedBuffer implements AutoCloseable { flush(); } - public ByteBuffer unwrap() { - return internal; - } - - public long getMemAddress() { - return MemoryUtil.memAddress(internal); + public long getPtr() { + return ptr; } public void clear(long clearStart, long clearLength) { @@ -64,7 +52,7 @@ public class MappedBuffer implements AutoCloseable { throw new IndexOutOfBoundsException("Clear range [" + clearStart + "," + (clearStart + clearLength) + "] is not mapped"); } - long addr = MemoryUtil.memAddress(unwrap()) + clearStart; + long addr = ptr + clearStart; MemoryUtil.memSet(addr, 0, clearLength); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedGlBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedGlBuffer.java deleted file mode 100644 index 6d0e5956b..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedGlBuffer.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.jozufozu.flywheel.backend.gl.buffer; - -import java.nio.ByteBuffer; - -import org.lwjgl.opengl.GL30; -import org.lwjgl.opengl.GL32; - -import com.jozufozu.flywheel.backend.gl.error.GlError; -import com.jozufozu.flywheel.backend.gl.error.GlException; - -public class MappedGlBuffer extends GlBuffer { - - protected final GlBufferUsage usage; - - public MappedGlBuffer(GlBufferType type) { - this(type, GlBufferUsage.STATIC_DRAW); - } - - public MappedGlBuffer(GlBufferType type, GlBufferUsage usage) { - super(type); - this.usage = usage; - } - - @Override - public boolean ensureCapacity(long size) { - if (size < 0) { - throw new IllegalArgumentException("Size " + size + " < 0"); - } - - if (size == 0) { - return false; - } - - if (this.size == 0) { - this.size = size; - bind(); - GL32.glBufferData(type.glEnum, size, usage.glEnum); - - return true; - } - - if (size > this.size) { - var oldSize = this.size; - this.size = size + growthMargin; - - realloc(oldSize, this.size); - - return true; - } - - return false; - } - - private void realloc(long oldSize, long newSize) { - var oldHandle = handle(); - var newHandle = GL32.glGenBuffers(); - - GlBufferType.COPY_READ_BUFFER.bind(oldHandle); - type.bind(newHandle); - - GL32.glBufferData(type.glEnum, newSize, usage.glEnum); - GL32.glCopyBufferSubData(GlBufferType.COPY_READ_BUFFER.glEnum, type.glEnum, 0, 0, oldSize); - - delete(); - setHandle(newHandle); - } - - @Override - public void upload(ByteBuffer directBuffer) { - bind(); - GL32.glBufferData(type.glEnum, directBuffer, usage.glEnum); - this.size = directBuffer.capacity(); - } - - @Override - public MappedBuffer map() { - bind(); - ByteBuffer byteBuffer = GL30.glMapBufferRange(type.glEnum, 0, size, GL30.GL_MAP_WRITE_BIT); - - if (byteBuffer == null) { - throw new GlException(GlError.poll(), "Could not map buffer"); - } - - return new MappedBuffer(this, byteBuffer, 0, size); - } - - @Override - public boolean isPersistent() { - return false; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java deleted file mode 100644 index e0ffa6c26..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.jozufozu.flywheel.backend.gl.buffer; - -import static org.lwjgl.opengl.GL30.GL_MAP_WRITE_BIT; -import static org.lwjgl.opengl.GL44.GL_MAP_COHERENT_BIT; -import static org.lwjgl.opengl.GL44.GL_MAP_PERSISTENT_BIT; - -import java.nio.ByteBuffer; - -import org.jetbrains.annotations.Nullable; -import org.lwjgl.opengl.GL32; -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.backend.gl.error.GlError; -import com.jozufozu.flywheel.backend.gl.error.GlException; -import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; - -public class PersistentGlBuffer extends GlBuffer { - - @Nullable - private MappedBuffer access; - private final int storageFlags; - - public PersistentGlBuffer(GlBufferType type) { - super(type); - - storageFlags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT; - } - - @Override - public boolean ensureCapacity(long size) { - if (size < 0) { - throw new IllegalArgumentException("Size " + size + " < 0"); - } - - if (size == 0) { - return false; - } - - if (this.size == 0) { - this.size = size; - bind(); - GlCompat.getInstance().bufferStorage.bufferStorage(type, this.size, storageFlags); - return true; - } - - if (size > this.size) { - var oldSize = this.size; - this.size = size + growthMargin; - - realloc(this.size, oldSize); - - access = null; - return true; - } - - return false; - } - - @Override - public void upload(ByteBuffer directBuffer) { - ensureCapacity(directBuffer.capacity()); - - var access = getWriteAccess(); - - ByteBuffer ourBuffer = access.unwrap(); - - ourBuffer.reset(); - - MemoryUtil.memCopy(directBuffer, ourBuffer); - - int uploadSize = directBuffer.remaining(); - int ourSize = ourBuffer.capacity(); - - if (uploadSize < ourSize) { - long clearFrom = access.getMemAddress() + uploadSize; - MemoryUtil.memSet(clearFrom, 0, ourSize - uploadSize); - } - } - - private void mapToClientMemory() { - bind(); - ByteBuffer byteBuffer = GL32.glMapBufferRange(type.glEnum, 0, size, storageFlags); - - if (byteBuffer == null) { - throw new GlException(GlError.poll(), "Could not map buffer"); - } - - access = new MappedBuffer(this, byteBuffer, 0, size); - } - - private void realloc(long newSize, long oldSize) { - int oldHandle = handle(); - int newHandle = GL32.glGenBuffers(); - - GlBufferType.COPY_READ_BUFFER.bind(oldHandle); - type.bind(newHandle); - - GlCompat.getInstance().bufferStorage.bufferStorage(type, newSize, storageFlags); - - GL32.glCopyBufferSubData(GlBufferType.COPY_READ_BUFFER.glEnum, type.glEnum, 0, 0, oldSize); - - delete(); - setHandle(newHandle); - } - - @Override - public MappedBuffer map() { - return getWriteAccess() - .position(0); - } - - private MappedBuffer getWriteAccess() { - if (access == null) { - mapToClientMemory(); - } - - return access; - } - - @Override - public boolean isPersistent() { - return true; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java b/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java index 972962dc3..8380d111e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java @@ -8,7 +8,6 @@ import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL20C; import org.lwjgl.opengl.GLCapabilities; import org.lwjgl.system.MemoryStack; -import org.lwjgl.system.MemoryUtil; import net.minecraft.Util; @@ -78,7 +77,7 @@ public class GlCompat { } /** - * Copied from: + * Modified from: *
canvas * *

Identical in function to {@link GL20C#glShaderSource(int, CharSequence)} but @@ -90,18 +89,11 @@ public class GlCompat { *

Hat tip to fewizz for the find and the fix. */ public static void safeShaderSource(int glId, CharSequence source) { - final MemoryStack stack = MemoryStack.stackGet(); - final int stackPointer = stack.getPointer(); - - try { - final ByteBuffer sourceBuffer = MemoryUtil.memUTF8(source, true); + try (MemoryStack stack = MemoryStack.stackPush()) { + final ByteBuffer sourceBuffer = stack.UTF8(source, true); final PointerBuffer pointers = stack.mallocPointer(1); pointers.put(sourceBuffer); - GL20C.nglShaderSource(glId, 1, pointers.address0(), 0); - org.lwjgl.system.APIUtil.apiArrayFree(pointers.address0(), 1); - } finally { - stack.setPointer(stackPointer); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java index 4b5d4c0a0..9bbcc3c2e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java @@ -7,7 +7,6 @@ import java.util.List; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.instancer.Instancer; import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.api.struct.StructWriter; public abstract class AbstractInstancer implements Instancer { @@ -114,22 +113,6 @@ public abstract class AbstractInstancer implements Inst return instanceData; } - protected void writeChangedUnchecked(StructWriter writer) { - boolean sequential = true; - for (int i = 0; i < data.size(); i++) { - final D element = data.get(i); - if (element.checkDirtyAndClear()) { - if (!sequential) { - writer.seek(i); - } - writer.write(element); - sequential = true; - } else { - sequential = false; - } - } - } - public abstract void delete(); @Override diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java index 8c5317223..79b1c78b7 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java @@ -28,7 +28,7 @@ import net.minecraft.world.level.block.entity.BlockEntity; * The instancer manager is shared between the different instance managers. *

*/ -public class InstanceWorld { +public class InstanceWorld implements AutoCloseable { protected final Engine engine; protected final InstanceManager entities; protected final InstanceManager blockEntities; @@ -148,4 +148,8 @@ public class InstanceWorld { .forEach(entities::add); } + @Override + public void close() { + delete(); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java index 00fb68cd6..65ea1cab7 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java @@ -13,9 +13,7 @@ import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.core.RenderContext; import com.jozufozu.flywheel.util.FlwUtil; -import com.mojang.blaze3d.platform.Lighting; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Matrix4f; import net.minecraft.client.Camera; import net.minecraft.client.multiplayer.ClientLevel; @@ -68,19 +66,11 @@ public class BatchingEngine implements Engine { @Override public void renderStage(TaskEngine taskEngine, RenderContext context, RenderStage stage) { // FIXME: properly support material stages + // This also breaks block outlines on batched block entities if (stage != RenderStage.AFTER_FINAL_END_BATCH) { return; } - // FIXME: this probably breaks some vanilla stuff but it works much better for flywheel - Matrix4f mat = new Matrix4f(); - mat.setIdentity(); - if (context.level().effects().constantAmbientLight()) { - Lighting.setupNetherLevel(mat); - } else { - Lighting.setupLevel(mat); - } - batchTracker.endBatch(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/DrawBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/DrawBuffer.java index e583f85e1..4e2cd4fc9 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/DrawBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/DrawBuffer.java @@ -2,28 +2,35 @@ package com.jozufozu.flywheel.backend.instancing.batching; import java.nio.ByteBuffer; -import org.lwjgl.system.MemoryUtil; - -import com.mojang.blaze3d.platform.MemoryTracker; +import com.jozufozu.flywheel.api.vertex.ReusableVertexList; +import com.jozufozu.flywheel.api.vertex.VertexListProvider; +import com.jozufozu.flywheel.backend.memory.MemoryBlock; +import com.jozufozu.flywheel.core.vertex.VertexListProviderRegistry; +import com.mojang.blaze3d.vertex.VertexFormat; import net.minecraft.client.renderer.RenderType; /** - * A byte buffer that can be used to draw vertices through multiple {@link MutableVertexListImpl}s. + * A byte buffer that can be used to draw vertices through multiple {@link ReusableVertexList}s. * * The number of vertices needs to be known ahead of time. */ public class DrawBuffer { private final RenderType parent; - private final VertexFormatInfo formatInfo; + private final VertexFormat format; + private final int stride; + private final VertexListProvider provider; + + private MemoryBlock memory; + private ByteBuffer buffer; - private ByteBuffer backingBuffer; private int expectedVertices; - private long ptr; public DrawBuffer(RenderType parent) { this.parent = parent; - formatInfo = new VertexFormatInfo(parent.format()); + format = parent.format(); + stride = format.getVertexSize(); + provider = VertexListProviderRegistry.getOrInfer(format); } /** @@ -33,29 +40,32 @@ public class DrawBuffer { */ public void prepare(int vertexCount) { if (expectedVertices != 0) { - throw new IllegalStateException("Already drawing"); + throw new IllegalStateException("Already drawing!"); } this.expectedVertices = vertexCount; // Add one extra vertex to uphold the vanilla assumption that BufferBuilders have at least - // enough buffer space for one more vertex. Sodium checks for this extra space when popNextBuffer + // enough buffer space for one more vertex. Rubidium checks for this extra space when popNextBuffer // is called and reallocates the buffer if there is not space for one more vertex. - int byteSize = formatInfo.stride * (vertexCount + 1); + int byteSize = stride * (vertexCount + 1); - if (backingBuffer == null) { - backingBuffer = MemoryTracker.create(byteSize); - } else if (byteSize > backingBuffer.capacity()) { - backingBuffer = MemoryTracker.resize(backingBuffer, byteSize); + if (memory == null) { + memory = MemoryBlock.malloc(byteSize); + buffer = memory.asBuffer(); + } else if (byteSize > memory.size()) { + memory = memory.realloc(byteSize); + buffer = memory.asBuffer(); } - backingBuffer.clear(); - ptr = MemoryUtil.memAddress(backingBuffer); - MemoryUtil.memSet(ptr, 0, byteSize); + memory.clear(); } - public MutableVertexListImpl slice(int startVertex, int vertexCount) { - return new MutableVertexListImpl(ptr + startVertex * formatInfo.stride, formatInfo, vertexCount); + public ReusableVertexList slice(int startVertex, int vertexCount) { + ReusableVertexList vertexList = provider.createVertexList(); + vertexList.ptr(memory.ptr() + startVertex * stride); + vertexList.setVertexCount(vertexCount); + return vertexList; } /** @@ -63,7 +73,8 @@ public class DrawBuffer { * @param bufferBuilder The buffer builder to inject into. */ public void inject(BufferBuilderExtension bufferBuilder) { - bufferBuilder.flywheel$injectForRender(backingBuffer, formatInfo.format, expectedVertices); + buffer.clear(); + bufferBuilder.flywheel$injectForRender(buffer, format, expectedVertices); } public int getVertexCount() { @@ -78,11 +89,16 @@ public class DrawBuffer { } /** - * Reset the draw buffer to have no vertices. + * Reset the draw buffer to have no vertices.

* * Does not clear the backing buffer. */ public void reset() { this.expectedVertices = 0; } + + public void free() { + buffer = null; + memory.free(); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/MutableVertexListImpl.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/MutableVertexListImpl.java deleted file mode 100644 index 410da67af..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/MutableVertexListImpl.java +++ /dev/null @@ -1,206 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.batching; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.api.vertex.MutableVertexList; -import com.jozufozu.flywheel.util.RenderMath; - -public class MutableVertexListImpl extends VertexFormatInfo implements MutableVertexList { - private final long anchorPtr; - private final int totalVertexCount; - - private long ptr; - private int vertexCount; - - public MutableVertexListImpl(long ptr, VertexFormatInfo formatInfo, int vertexCount) { - super(formatInfo); - - anchorPtr = ptr; - totalVertexCount = vertexCount; - - setFullRange(); - } - - public void setRange(int startVertex, int vertexCount) { - ptr = anchorPtr + startVertex * stride; - this.vertexCount = vertexCount; - } - - public void setFullRange() { - ptr = anchorPtr; - vertexCount = totalVertexCount; - } - - @Override - public float x(int index) { - if (positionOffset < 0) return 0; - return MemoryUtil.memGetFloat(ptr + index * stride + positionOffset); - } - - @Override - public float y(int index) { - if (positionOffset < 0) return 0; - return MemoryUtil.memGetFloat(ptr + index * stride + positionOffset + 4); - } - - @Override - public float z(int index) { - if (positionOffset < 0) return 0; - return MemoryUtil.memGetFloat(ptr + index * stride + positionOffset + 8); - } - - @Override - public byte r(int index) { - if (colorOffset < 0) return 0; - return MemoryUtil.memGetByte(ptr + index * stride + colorOffset); - } - - @Override - public byte g(int index) { - if (colorOffset < 0) return 0; - return MemoryUtil.memGetByte(ptr + index * stride + colorOffset + 1); - } - - @Override - public byte b(int index) { - if (colorOffset < 0) return 0; - return MemoryUtil.memGetByte(ptr + index * stride + colorOffset + 2); - } - - @Override - public byte a(int index) { - if (colorOffset < 0) return 0; - return MemoryUtil.memGetByte(ptr + index * stride + colorOffset + 3); - } - - @Override - public float u(int index) { - if (textureOffset < 0) return 0; - return MemoryUtil.memGetFloat(ptr + index * stride + textureOffset); - } - - @Override - public float v(int index) { - if (textureOffset < 0) return 0; - return MemoryUtil.memGetFloat(ptr + index * stride + textureOffset + 4); - } - - @Override - public int overlay(int index) { - if (overlayOffset < 0) return 0; - return MemoryUtil.memGetInt(ptr + index * stride + overlayOffset); - } - - @Override - public int light(int index) { - if (lightOffset < 0) return 0; - return MemoryUtil.memGetInt(ptr + index * stride + lightOffset); - } - - @Override - public float normalX(int index) { - if (normalOffset < 0) return 0; - return RenderMath.f(MemoryUtil.memGetByte(ptr + index * stride + normalOffset)); - } - - @Override - public float normalY(int index) { - if (normalOffset < 0) return 0; - return RenderMath.f(MemoryUtil.memGetByte(ptr + index * stride + normalOffset + 1)); - } - - @Override - public float normalZ(int index) { - if (normalOffset < 0) return 0; - return RenderMath.f(MemoryUtil.memGetByte(ptr + index * stride + normalOffset + 2)); - } - - @Override - public int getVertexCount() { - return vertexCount; - } - - @Override - public void x(int index, float x) { - if (positionOffset < 0) return; - MemoryUtil.memPutFloat(ptr + index * stride + positionOffset, x); - } - - @Override - public void y(int index, float y) { - if (positionOffset < 0) return; - MemoryUtil.memPutFloat(ptr + index * stride + positionOffset + 4, y); - } - - @Override - public void z(int index, float z) { - if (positionOffset < 0) return; - MemoryUtil.memPutFloat(ptr + index * stride + positionOffset + 8, z); - } - - @Override - public void r(int index, byte r) { - if (colorOffset < 0) return; - MemoryUtil.memPutByte(ptr + index * stride + colorOffset, r); - } - - @Override - public void g(int index, byte g) { - if (colorOffset < 0) return; - MemoryUtil.memPutByte(ptr + index * stride + colorOffset + 1, g); - } - - @Override - public void b(int index, byte b) { - if (colorOffset < 0) return; - MemoryUtil.memPutByte(ptr + index * stride + colorOffset + 2, b); - } - - @Override - public void a(int index, byte a) { - if (colorOffset < 0) return; - MemoryUtil.memPutByte(ptr + index * stride + colorOffset + 3, a); - } - - @Override - public void u(int index, float u) { - if (textureOffset < 0) return; - MemoryUtil.memPutFloat(ptr + index * stride + textureOffset, u); - } - - @Override - public void v(int index, float v) { - if (textureOffset < 0) return; - MemoryUtil.memPutFloat(ptr + index * stride + textureOffset + 4, v); - } - - @Override - public void overlay(int index, int overlay) { - if (overlayOffset < 0) return; - MemoryUtil.memPutInt(ptr + index * stride + overlayOffset, overlay); - } - - @Override - public void light(int index, int light) { - if (lightOffset < 0) return; - MemoryUtil.memPutInt(ptr + index * stride + lightOffset, light); - } - - @Override - public void normalX(int index, float normalX) { - if (normalOffset < 0) return; - MemoryUtil.memPutByte(ptr + index * stride + normalOffset, RenderMath.nb(normalX)); - } - - @Override - public void normalY(int index, float normalY) { - if (normalOffset < 0) return; - MemoryUtil.memPutByte(ptr + index * stride + normalOffset + 1, RenderMath.nb(normalY)); - } - - @Override - public void normalZ(int index, float normalZ) { - if (normalOffset < 0) return; - MemoryUtil.memPutByte(ptr + index * stride + normalOffset + 2, RenderMath.nb(normalZ)); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformSet.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformSet.java index 642fea29f..bb1fb6185 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformSet.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformSet.java @@ -5,9 +5,8 @@ import java.util.List; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.api.struct.StructType.VertexTransformer; import com.jozufozu.flywheel.api.vertex.MutableVertexList; -import com.jozufozu.flywheel.api.vertex.VertexList; +import com.jozufozu.flywheel.api.vertex.ReusableVertexList; import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.core.model.Mesh; import com.mojang.blaze3d.vertex.PoseStack; @@ -49,80 +48,50 @@ public class TransformSet { int start = Math.max(instances, 0); int vertexCount = mesh.getVertexCount() * (end - start); - MutableVertexListImpl sub = buffer.slice(startVertex, vertexCount); + ReusableVertexList sub = buffer.slice(startVertex, vertexCount); startVertex += vertexCount; pool.submit(() -> drawRange(sub, start, end, stack, level)); } } - private void drawRange(MutableVertexListImpl vertexList, int from, int to, PoseStack stack, ClientLevel level) { + private void drawRange(ReusableVertexList vertexList, int from, int to, PoseStack stack, ClientLevel level) { drawList(vertexList, instancer.getRange(from, to), stack, level); } - void drawAll(MutableVertexListImpl vertexList, PoseStack stack, ClientLevel level) { + void drawAll(ReusableVertexList vertexList, PoseStack stack, ClientLevel level) { drawList(vertexList, instancer.getAll(), stack, level); } - private void drawList(MutableVertexListImpl vertexList, List list, PoseStack stack, ClientLevel level) { - int startVertex = 0; - int meshVertexCount = mesh.getVertexCount(); + private void drawList(ReusableVertexList vertexList, List list, PoseStack stack, ClientLevel level) { + long anchorPtr = vertexList.ptr(); + int totalVertexCount = vertexList.getVertexCount(); - VertexList meshReader = mesh.getReader(); - @SuppressWarnings("unchecked") - StructType.VertexTransformer structVertexTransformer = (VertexTransformer) instancer.type.getVertexTransformer(); + int meshVertexCount = mesh.getVertexCount(); + vertexList.setVertexCount(meshVertexCount); + + StructType.VertexTransformer structVertexTransformer = instancer.type.getVertexTransformer(); for (D d : list) { - vertexList.setRange(startVertex, meshVertexCount); - - writeMesh(vertexList, meshReader); + mesh.write(vertexList); structVertexTransformer.transform(vertexList, d, level); - startVertex += meshVertexCount; + vertexList.shiftPtr(meshVertexCount); } - vertexList.setFullRange(); + vertexList.ptr(anchorPtr); + vertexList.setVertexCount(totalVertexCount); material.getVertexTransformer().transform(vertexList, level); - applyPoseStack(vertexList, stack, false); + applyPoseStack(vertexList, stack); } - // TODO: remove this - // The VertexWriter API and VertexFormat conversion needs to be rewritten to make this unnecessary - private static void writeMesh(MutableVertexList vertexList, VertexList meshReader) { - for (int i = 0; i < meshReader.getVertexCount(); i++) { - vertexList.x(i, meshReader.x(i)); - vertexList.y(i, meshReader.y(i)); - vertexList.z(i, meshReader.z(i)); - - vertexList.r(i, meshReader.r(i)); - vertexList.g(i, meshReader.g(i)); - vertexList.b(i, meshReader.b(i)); - vertexList.a(i, meshReader.a(i)); - - vertexList.u(i, meshReader.u(i)); - vertexList.v(i, meshReader.v(i)); - - vertexList.overlay(i, meshReader.overlay(i)); - vertexList.light(i, meshReader.light(i)); - - vertexList.normalX(i, meshReader.normalX(i)); - vertexList.normalY(i, meshReader.normalY(i)); - vertexList.normalZ(i, meshReader.normalZ(i)); - } - } - - private static void applyPoseStack(MutableVertexList vertexList, PoseStack stack, boolean applyNormalMatrix) { + private static void applyPoseStack(MutableVertexList vertexList, PoseStack stack) { Vector4f pos = new Vector4f(); Vector3f normal = new Vector3f(); Matrix4f modelMatrix = stack.last().pose(); - Matrix3f normalMatrix; - if (applyNormalMatrix) { - normalMatrix = stack.last().normal(); - } else { - normalMatrix = null; - } + Matrix3f normalMatrix = stack.last().normal(); for (int i = 0; i < vertexList.getVertexCount(); i++) { pos.set( @@ -136,18 +105,16 @@ public class TransformSet { vertexList.y(i, pos.y()); vertexList.z(i, pos.z()); - if (applyNormalMatrix) { - normal.set( - vertexList.normalX(i), - vertexList.normalY(i), - vertexList.normalZ(i) - ); - normal.transform(normalMatrix); - normal.normalize(); - vertexList.normalX(i, normal.x()); - vertexList.normalY(i, normal.y()); - vertexList.normalZ(i, normal.z()); - } + normal.set( + vertexList.normalX(i), + vertexList.normalY(i), + vertexList.normalZ(i) + ); + normal.transform(normalMatrix); + normal.normalize(); + vertexList.normalX(i, normal.x()); + vertexList.normalY(i, normal.y()); + vertexList.normalZ(i, normal.z()); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java index a46ce4f7c..7689ca9a2 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java @@ -10,8 +10,8 @@ import com.jozufozu.flywheel.api.instancer.InstancerFactory; import com.jozufozu.flywheel.api.instancer.InstancerManager; import com.jozufozu.flywheel.backend.instancing.AbstractInstance; import com.jozufozu.flywheel.core.structs.StructTypes; -import com.jozufozu.flywheel.core.structs.model.TransformedPart; import com.jozufozu.flywheel.core.structs.oriented.OrientedPart; +import com.jozufozu.flywheel.core.structs.transformed.TransformedPart; import com.jozufozu.flywheel.util.box.GridAlignedBB; import com.jozufozu.flywheel.util.box.ImmutableBox; import com.jozufozu.flywheel.util.joml.FrustumIntersection; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectMeshPool.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectMeshPool.java index 1ae8f1722..367e4ffdb 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectMeshPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectMeshPool.java @@ -13,6 +13,7 @@ import org.lwjgl.system.MemoryUtil; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.instancing.instancing.ElementBuffer; +import com.jozufozu.flywheel.backend.memory.MemoryBlock; import com.jozufozu.flywheel.core.model.Mesh; public class IndirectMeshPool { @@ -23,7 +24,7 @@ public class IndirectMeshPool { final VertexType vertexType; final int vbo; - private final ByteBuffer clientStorage; + private final MemoryBlock clientStorage; private boolean dirty; @@ -35,7 +36,7 @@ public class IndirectMeshPool { vbo = glCreateBuffers(); var byteCapacity = type.byteOffset(vertexCapacity); glNamedBufferStorage(vbo, byteCapacity, GL_DYNAMIC_STORAGE_BIT); - clientStorage = MemoryUtil.memAlloc(byteCapacity); + clientStorage = MemoryBlock.malloc(byteCapacity); } /** @@ -65,24 +66,25 @@ public class IndirectMeshPool { } dirty = false; + final long ptr = clientStorage.ptr(); + int byteIndex = 0; int baseVertex = 0; for (BufferedMesh model : meshList) { model.byteIndex = byteIndex; model.baseVertex = baseVertex; - model.buffer(clientStorage); + model.buffer(ptr); byteIndex += model.getByteSize(); baseVertex += model.mesh.getVertexCount(); } - clientStorage.rewind(); - - glNamedBufferSubData(vbo, 0, clientStorage); + nglNamedBufferSubData(vbo, 0, byteIndex, ptr); } public void delete() { + clientStorage.free(); glDeleteBuffers(vbo); meshes.clear(); meshList.clear(); @@ -101,10 +103,8 @@ public class IndirectMeshPool { vertexCount = mesh.getVertexCount(); } - private void buffer(ByteBuffer buffer) { - var writer = IndirectMeshPool.this.vertexType.createWriter(buffer); - writer.seek(this.byteIndex); - writer.writeVertexList(this.mesh.getReader()); + private void buffer(long ptr) { + this.mesh.write(ptr + byteIndex); } public int getByteSize() { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java index bcc39f82e..a2fc2da05 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java @@ -6,12 +6,12 @@ import java.util.Set; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.struct.StructType; +import com.jozufozu.flywheel.api.struct.StructWriter; import com.jozufozu.flywheel.backend.gl.array.GlVertexArray; import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferUsage; import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer; -import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer; import com.jozufozu.flywheel.backend.instancing.AbstractInstancer; import com.jozufozu.flywheel.core.layout.BufferLayout; @@ -42,7 +42,7 @@ public class GPUInstancer extends AbstractInstancer public void init() { if (vbo != null) return; - vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER, GlBufferUsage.DYNAMIC_DRAW); + vbo = new GlBuffer(GlBufferType.ARRAY_BUFFER, GlBufferUsage.DYNAMIC_DRAW); vbo.setGrowthMargin(instanceFormat.getStride() * 16); } @@ -88,7 +88,16 @@ public class GPUInstancer extends AbstractInstancer buf.clear(clearStart, clearLength); if (size > 0) { - writeChangedUnchecked(structType.getWriter(buf.unwrap())); + final long ptr = buf.getPtr(); + final long stride = structType.getLayout().getStride(); + final StructWriter writer = structType.getWriter(); + + for (int i = 0; i < size; i++) { + final D element = data.get(i); + if (element.checkDirtyAndClear()) { + writer.write(ptr + i * stride, element); + } + } } } catch (Exception e) { Flywheel.LOGGER.error("Error updating GPUInstancer:", e); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/MeshPool.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/MeshPool.java index 0438ac71d..919e863d7 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/MeshPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/MeshPool.java @@ -1,6 +1,5 @@ package com.jozufozu.flywheel.backend.instancing.instancing; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -18,7 +17,7 @@ import com.jozufozu.flywheel.backend.gl.array.GlVertexArray; import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer; -import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer; +import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.model.Mesh; import com.jozufozu.flywheel.core.vertex.Formats; import com.jozufozu.flywheel.event.ReloadRenderersEvent; @@ -27,7 +26,7 @@ public class MeshPool { private static MeshPool allocator; - static MeshPool getInstance() { + public static MeshPool getInstance() { if (allocator == null) { allocator = new MeshPool(); } @@ -58,7 +57,7 @@ public class MeshPool { * Create a new mesh pool. */ public MeshPool() { - vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER); + vbo = new GlBuffer(GlBufferType.ARRAY_BUFFER); vbo.setGrowthMargin(2048); } @@ -71,9 +70,8 @@ public class MeshPool { */ public BufferedMesh alloc(Mesh mesh) { return meshes.computeIfAbsent(mesh, m -> { - // FIXME: culling experiments fixing everything to Formats.BLOCK - BufferedMesh bufferedModel = new BufferedMesh(Formats.BLOCK, m, byteSize, vertexCount); - byteSize += bufferedModel.getByteSize(); + BufferedMesh bufferedModel = new BufferedMesh(m, byteSize, vertexCount); + byteSize += m.size(); vertexCount += bufferedModel.mesh.getVertexCount(); allBuffered.add(bufferedModel); pendingUpload.add(bufferedModel); @@ -147,7 +145,7 @@ public class MeshPool { private void uploadAll() { try (MappedBuffer mapped = vbo.map()) { - ByteBuffer buffer = mapped.unwrap(); + long ptr = mapped.getPtr(); int byteIndex = 0; int baseVertex = 0; @@ -155,26 +153,26 @@ public class MeshPool { model.byteIndex = byteIndex; model.baseVertex = baseVertex; - model.buffer(buffer); + model.buffer(ptr); byteIndex += model.getByteSize(); baseVertex += model.mesh.getVertexCount(); } } catch (Exception e) { - Flywheel.LOGGER.error("Error uploading pooled models:", e); + Flywheel.LOGGER.error("Error uploading pooled meshes:", e); } } private void uploadPending() { try (MappedBuffer mapped = vbo.map()) { - ByteBuffer buffer = mapped.unwrap(); + long buffer = mapped.getPtr(); for (BufferedMesh model : pendingUpload) { model.buffer(buffer); } pendingUpload.clear(); } catch (Exception e) { - Flywheel.LOGGER.error("Error uploading pooled models:", e); + Flywheel.LOGGER.error("Error uploading pooled meshes:", e); } } @@ -207,14 +205,6 @@ public class MeshPool { this.type = mesh.getVertexType(); } - public BufferedMesh(VertexType type, Mesh mesh, long byteIndex, int baseVertex) { - this.mesh = mesh; - this.byteIndex = byteIndex; - this.baseVertex = baseVertex; - this.ebo = mesh.createEBO(); - this.type = type; - } - public void drawCall(GlVertexArray vao) { drawInstances(vao, 1); } @@ -228,7 +218,7 @@ public class MeshPool { } private boolean hasAnythingToRender() { - return mesh.getVertexCount() <= 0 || isDeleted(); + return mesh.isEmpty() || isDeleted(); } private void draw(int instanceCount) { @@ -258,10 +248,8 @@ public class MeshPool { this.deleted = true; } - private void buffer(ByteBuffer buffer) { - var writer = type.createWriter(buffer); - writer.seek(this.byteIndex); - writer.writeVertexList(this.mesh.getReader()); + private void buffer(long ptr) { + this.mesh.write(ptr + byteIndex); this.boundTo.clear(); this.gpuResident = true; diff --git a/src/main/java/com/jozufozu/flywheel/backend/memory/FlwMemoryTracker.java b/src/main/java/com/jozufozu/flywheel/backend/memory/FlwMemoryTracker.java new file mode 100644 index 000000000..165b441f3 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/memory/FlwMemoryTracker.java @@ -0,0 +1,111 @@ +package com.jozufozu.flywheel.backend.memory; + +import java.lang.ref.Cleaner; +import java.nio.ByteBuffer; + +import org.lwjgl.system.MemoryUtil; + +public class FlwMemoryTracker { + static final Cleaner CLEANER = Cleaner.create(); + + private static long cpuMemory = 0; + private static long gpuMemory = 0; + + public static long malloc(long size) { + long ptr = MemoryUtil.nmemAlloc(size); + if (ptr == MemoryUtil.NULL) { + throw new OutOfMemoryError("Failed to allocate " + size + " bytes"); + } + return ptr; + } + + /** + * @deprecated Use {@link MemoryBlock#malloc(long)} or {@link MemoryBlock#mallocTracked(long)} and + * {@link MemoryBlock#asBuffer()} instead. This method should only be used if specifically a {@linkplain ByteBuffer} is needed and it is + * short-lived. + */ + @Deprecated + public static ByteBuffer mallocBuffer(int size) { + ByteBuffer buffer = MemoryUtil.memByteBuffer(malloc(size), size); + _allocCPUMemory(buffer.capacity()); + return buffer; + } + + public static long calloc(long num, long size) { + long ptr = MemoryUtil.nmemCalloc(num, size); + if (ptr == MemoryUtil.NULL) { + throw new OutOfMemoryError("Failed to allocate " + num + " elements of size " + size + " bytes"); + } + return ptr; + } + + /** + * @deprecated Use {@link MemoryBlock#calloc(long, long)} or {@link MemoryBlock#callocTracked(long, long)} and + * {@link MemoryBlock#asBuffer()} instead. This method should only be used if specifically a {@linkplain ByteBuffer} is needed and it is + * short-lived. + */ + @Deprecated + public static ByteBuffer callocBuffer(int num, int size) { + ByteBuffer buffer = MemoryUtil.memByteBuffer(calloc(num, size), num * size); + _allocCPUMemory(buffer.capacity()); + return buffer; + } + + public static long realloc(long ptr, long size) { + ptr = MemoryUtil.nmemRealloc(ptr, size); + if (ptr == MemoryUtil.NULL) { + throw new OutOfMemoryError("Failed to reallocate " + size + " bytes for address 0x" + Long.toHexString(ptr)); + } + return ptr; + } + + /** + * @deprecated Use {@link MemoryBlock#realloc(long)} or {@link MemoryBlock#reallocTracked(long)} instead. This method + * should only be used if specifically a {@linkplain ByteBuffer} is needed and it is short-lived. + */ + @Deprecated + public static ByteBuffer reallocBuffer(ByteBuffer buffer, int size) { + ByteBuffer newBuffer = MemoryUtil.memByteBuffer(realloc(MemoryUtil.memAddress(buffer), size), size); + _freeCPUMemory(buffer.capacity()); + _allocCPUMemory(newBuffer.capacity()); + return newBuffer; + } + + public static void free(long ptr) { + MemoryUtil.nmemFree(ptr); + } + + /** + * @deprecated Use {@link MemoryBlock#free} instead. This method should only be used if specifically a {@linkplain ByteBuffer} is needed and + * it is short-lived. + */ + @Deprecated + public static void freeBuffer(ByteBuffer buffer) { + free(MemoryUtil.memAddress(buffer)); + _freeCPUMemory(buffer.capacity()); + } + + public static void _allocCPUMemory(long size) { + cpuMemory += size; + } + + public static void _freeCPUMemory(long size) { + cpuMemory -= size; + } + + public static void _allocGPUMemory(long size) { + gpuMemory += size; + } + + public static void _freeGPUMemory(long size) { + gpuMemory -= size; + } + + public static long getCPUMemory() { + return cpuMemory; + } + + public static long getGPUMemory() { + return gpuMemory; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/memory/MemoryBlock.java b/src/main/java/com/jozufozu/flywheel/backend/memory/MemoryBlock.java new file mode 100644 index 000000000..1b28bdbe2 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/memory/MemoryBlock.java @@ -0,0 +1,43 @@ +package com.jozufozu.flywheel.backend.memory; + +import java.nio.ByteBuffer; + +public sealed interface MemoryBlock permits MemoryBlockImpl { + long ptr(); + + long size(); + + boolean isFreed(); + + boolean isTracked(); + + void copyTo(long ptr, long bytes); + + void copyTo(long ptr); + + void clear(); + + ByteBuffer asBuffer(); + + MemoryBlock realloc(long size); + + MemoryBlock reallocTracked(long size); + + void free(); + + static MemoryBlock malloc(long size) { + return MemoryBlockImpl.mallocBlock(size); + } + + static MemoryBlock mallocTracked(long size) { + return TrackedMemoryBlockImpl.mallocBlockTracked(size); + } + + static MemoryBlock calloc(long num, long size) { + return MemoryBlockImpl.callocBlock(num, size); + } + + static MemoryBlock callocTracked(long num, long size) { + return TrackedMemoryBlockImpl.callocBlockTracked(num, size); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/memory/MemoryBlockImpl.java b/src/main/java/com/jozufozu/flywheel/backend/memory/MemoryBlockImpl.java new file mode 100644 index 000000000..d37b61ded --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/memory/MemoryBlockImpl.java @@ -0,0 +1,100 @@ +package com.jozufozu.flywheel.backend.memory; + +import java.nio.ByteBuffer; + +import org.lwjgl.system.MemoryUtil; + +sealed class MemoryBlockImpl implements MemoryBlock permits TrackedMemoryBlockImpl { + final long ptr; + final long size; + + boolean freed; + + MemoryBlockImpl(long ptr, long size) { + this.ptr = ptr; + this.size = size; + } + + @Override + public long ptr() { + return ptr; + } + + @Override + public long size() { + return size; + } + + @Override + public boolean isFreed() { + return freed; + } + + @Override + public boolean isTracked() { + return false; + } + + @Override + public void copyTo(long ptr, long bytes) { + MemoryUtil.memCopy(this.ptr, ptr, bytes); + } + + @Override + public void copyTo(long ptr) { + copyTo(ptr, size); + } + + @Override + public void clear() { + MemoryUtil.memSet(ptr, 0, size); + } + + @Override + public ByteBuffer asBuffer() { + int intSize = (int) size; + if (intSize != size) { + throw new UnsupportedOperationException("Cannot create buffer with long capacity!"); + } + return MemoryUtil.memByteBuffer(ptr, intSize); + } + + void freeInner() { + FlwMemoryTracker._freeCPUMemory(size); + freed = true; + } + + @Override + public MemoryBlock realloc(long size) { + MemoryBlock block = new MemoryBlockImpl(FlwMemoryTracker.realloc(ptr, size), size); + FlwMemoryTracker._allocCPUMemory(block.size()); + freeInner(); + return block; + } + + @Override + public MemoryBlock reallocTracked(long size) { + MemoryBlock block = new TrackedMemoryBlockImpl(FlwMemoryTracker.realloc(ptr, size), size, FlwMemoryTracker.CLEANER); + FlwMemoryTracker._allocCPUMemory(block.size()); + freeInner(); + return block; + } + + @Override + public void free() { + FlwMemoryTracker.free(ptr); + freeInner(); + } + + static MemoryBlock mallocBlock(long size) { + MemoryBlock block = new MemoryBlockImpl(FlwMemoryTracker.malloc(size), size); + FlwMemoryTracker._allocCPUMemory(block.size()); + return block; + } + + static MemoryBlock callocBlock(long num, long size) { + MemoryBlock block = new MemoryBlockImpl(FlwMemoryTracker.calloc(num, size), num * size); + FlwMemoryTracker._allocCPUMemory(block.size()); + return block; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/memory/TrackedMemoryBlockImpl.java b/src/main/java/com/jozufozu/flywheel/backend/memory/TrackedMemoryBlockImpl.java new file mode 100644 index 000000000..57b7730c5 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/memory/TrackedMemoryBlockImpl.java @@ -0,0 +1,58 @@ +package com.jozufozu.flywheel.backend.memory; + +import java.lang.ref.Cleaner; + +final class TrackedMemoryBlockImpl extends MemoryBlockImpl { + final CleaningAction cleaningAction; + final Cleaner.Cleanable cleanable; + + TrackedMemoryBlockImpl(long ptr, long size, Cleaner cleaner) { + super(ptr, size); + cleaningAction = new CleaningAction(ptr, size); + cleanable = cleaner.register(this, cleaningAction); + } + + @Override + public boolean isTracked() { + return true; + } + + @Override + void freeInner() { + super.freeInner(); + cleaningAction.freed = true; + cleanable.clean(); + } + + static MemoryBlock mallocBlockTracked(long size) { + MemoryBlock block = new TrackedMemoryBlockImpl(FlwMemoryTracker.malloc(size), size, FlwMemoryTracker.CLEANER); + FlwMemoryTracker._allocCPUMemory(block.size()); + return block; + } + + static MemoryBlock callocBlockTracked(long num, long size) { + MemoryBlock block = new TrackedMemoryBlockImpl(FlwMemoryTracker.calloc(num, size), num * size, FlwMemoryTracker.CLEANER); + FlwMemoryTracker._allocCPUMemory(block.size()); + return block; + } + + static class CleaningAction implements Runnable { + final long ptr; + final long size; + + boolean freed; + + CleaningAction(long ptr, long size) { + this.ptr = ptr; + this.size = size; + } + + @Override + public void run() { + if (!freed) { + FlwMemoryTracker.free(ptr); + FlwMemoryTracker._freeCPUMemory(size); + } + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/struct/BufferWriter.java b/src/main/java/com/jozufozu/flywheel/backend/struct/BufferWriter.java deleted file mode 100644 index 49ce4969d..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/struct/BufferWriter.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.jozufozu.flywheel.backend.struct; - -import java.nio.ByteBuffer; - -import com.jozufozu.flywheel.api.instancer.InstancedPart; -import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.api.struct.StructWriter; - -public abstract class BufferWriter implements StructWriter { - protected final ByteBuffer backingBuffer; - - protected final int stride; - - protected BufferWriter(StructType structType, ByteBuffer byteBuffer) { - this.backingBuffer = byteBuffer; - - this.stride = structType.getLayout().getStride(); - } - - @Override - public final void write(S struct) { - writeInternal(struct); - advance(); - } - - /** - * Advances the write pointer forward by the stride of one vertex. - * This will always be called after a struct is written, implementors need not call it themselves. - * - * @see #write - */ - protected abstract void advance(); - - protected abstract void writeInternal(S s); - - @Override - public void seek(int pos) { - backingBuffer.position(pos * stride); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/struct/UnsafeBufferWriter.java b/src/main/java/com/jozufozu/flywheel/backend/struct/UnsafeBufferWriter.java deleted file mode 100644 index 7aa852de1..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/struct/UnsafeBufferWriter.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.jozufozu.flywheel.backend.struct; - -import java.nio.ByteBuffer; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.api.instancer.InstancedPart; -import com.jozufozu.flywheel.api.struct.StructType; - -/** - * This class copied/adapted from jellysquid's - * - * An unsafe {@link BufferWriter} implementation which uses direct memory operations to enable fast blitting of - * data into memory buffers. Only available on JVMs which support {@link sun.misc.Unsafe}, but generally produces much - * better optimized code than other implementations. The implementation does not check for invalid memory accesses, - * meaning that errors can corrupt process memory. - */ -public abstract class UnsafeBufferWriter extends BufferWriter { - /** - * The write pointer into the buffer storage. This is advanced by the stride every time - * {@link UnsafeBufferWriter#advance()} is called. - */ - protected long writePointer; - - protected UnsafeBufferWriter(StructType structType, ByteBuffer byteBuffer) { - super(structType, byteBuffer); - - acquireWritePointer(); - } - - @Override - public void seek(int pos) { - super.seek(pos); - acquireWritePointer(); - } - - @Override - protected void advance() { - this.writePointer += this.stride; - } - - private void acquireWritePointer() { - this.writePointer = MemoryUtil.memAddress(this.backingBuffer, this.backingBuffer.position()); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java b/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java index c3282c2ae..7280641fa 100644 --- a/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java +++ b/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java @@ -3,13 +3,14 @@ package com.jozufozu.flywheel.core; import static org.lwjgl.opengl.GL11.GL_TRIANGLES; import static org.lwjgl.opengl.GL11.glDrawArrays; +import org.lwjgl.system.MemoryUtil; + import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.backend.gl.GlStateTracker; import com.jozufozu.flywheel.backend.gl.array.GlVertexArray; import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer; -import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer; import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.layout.CommonItems; import com.jozufozu.flywheel.util.Lazy; @@ -34,13 +35,14 @@ public class FullscreenQuad { private FullscreenQuad() { try (var restoreState = GlStateTracker.getRestoreState()) { - vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER); + vbo = new GlBuffer(GlBufferType.ARRAY_BUFFER); vbo.ensureCapacity(bufferSize); try (MappedBuffer buffer = vbo.map()) { + var ptr = buffer.getPtr(); - buffer.unwrap() - .asFloatBuffer() - .put(vertices); + for (var i = 0; i < vertices.length; i++) { + MemoryUtil.memPutFloat(ptr + i * Float.BYTES, vertices[i]); + } } catch (Exception e) { Flywheel.LOGGER.error("Could not create fullscreen quad.", e); diff --git a/src/main/java/com/jozufozu/flywheel/core/QuadConverter.java b/src/main/java/com/jozufozu/flywheel/core/QuadConverter.java index 0b2477214..71e9d27ce 100644 --- a/src/main/java/com/jozufozu/flywheel/core/QuadConverter.java +++ b/src/main/java/com/jozufozu/flywheel/core/QuadConverter.java @@ -1,15 +1,13 @@ package com.jozufozu.flywheel.core; -import java.nio.ByteBuffer; - import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.lwjgl.system.MemoryUtil; import com.jozufozu.flywheel.backend.gl.GlNumericType; +import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer; -import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer; import com.jozufozu.flywheel.backend.instancing.instancing.ElementBuffer; import com.jozufozu.flywheel.event.ReloadRenderersEvent; @@ -34,11 +32,11 @@ public class QuadConverter { return INSTANCE; } - private final MappedGlBuffer ebo; + private final GlBuffer ebo; private int quadCapacity; public QuadConverter() { - this.ebo = new MappedGlBuffer(GlBufferType.ELEMENT_ARRAY_BUFFER); + this.ebo = new GlBuffer(GlBufferType.ELEMENT_ARRAY_BUFFER); this.quadCapacity = 0; } @@ -49,9 +47,7 @@ public class QuadConverter { ebo.ensureCapacity((long) indexCount * GlNumericType.UINT.getByteWidth()); try (MappedBuffer map = ebo.map()) { - ByteBuffer indices = map.unwrap(); - - fillBuffer(indices, quads); + fillBuffer(map.getPtr(), quads); } ebo.unbind(); @@ -66,32 +62,18 @@ public class QuadConverter { this.quadCapacity = 0; } - private void fillBuffer(ByteBuffer indices, int quads) { - long addr = MemoryUtil.memAddress(indices); + private void fillBuffer(long addr, int quads) { int numVertices = 4 * quads; int baseVertex = 0; while (baseVertex < numVertices) { - // writeQuadIndices(indices, baseVertex); - writeQuadIndicesUnsafe(addr, baseVertex); + writeQuadIndices(addr, baseVertex); baseVertex += 4; addr += 6 * 4; } - // ((Buffer) indices).flip(); } - private void writeQuadIndices(ByteBuffer indices, int baseVertex) { - // triangle a - indices.putInt(baseVertex); - indices.putInt(baseVertex + 1); - indices.putInt(baseVertex + 2); - // triangle b - indices.putInt(baseVertex); - indices.putInt(baseVertex + 2); - indices.putInt(baseVertex + 3); - } - - private void writeQuadIndicesUnsafe(long addr, int baseVertex) { + private void writeQuadIndices(long addr, int baseVertex) { // triangle a MemoryUtil.memPutInt(addr, baseVertex); MemoryUtil.memPutInt(addr + 4, baseVertex + 1); @@ -102,7 +84,7 @@ public class QuadConverter { MemoryUtil.memPutInt(addr + 20, baseVertex + 3); } - // make sure this gets reset first so it has a chance to repopulate + // make sure this gets reset first, so it has a chance to repopulate public static void onRendererReload(ReloadRenderersEvent event) { if (INSTANCE != null) { INSTANCE.delete(); diff --git a/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java b/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java index 91620e819..b381d859b 100644 --- a/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java +++ b/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java @@ -2,74 +2,86 @@ package com.jozufozu.flywheel.core.hardcoded; import java.util.List; -import org.jetbrains.annotations.NotNull; -import org.lwjgl.system.MemoryStack; - -import com.jozufozu.flywheel.api.vertex.VertexList; +import com.jozufozu.flywheel.api.vertex.MutableVertexList; +import com.jozufozu.flywheel.api.vertex.ReusableVertexList; +import com.jozufozu.flywheel.backend.memory.MemoryBlock; import com.jozufozu.flywheel.core.model.Mesh; import com.jozufozu.flywheel.core.model.ModelUtil; import com.jozufozu.flywheel.core.vertex.Formats; import com.jozufozu.flywheel.core.vertex.PosTexNormalVertex; -import com.jozufozu.flywheel.core.vertex.PosTexNormalWriterUnsafe; import com.jozufozu.flywheel.util.joml.Vector4f; import com.jozufozu.flywheel.util.joml.Vector4fc; public class ModelPart implements Mesh { - - private final int vertices; + private final int vertexCount; + private final MemoryBlock contents; + private final ReusableVertexList vertexList; private final String name; - private final VertexList reader; - private final @NotNull Vector4f boundingSphere; + private final Vector4f boundingSphere; public ModelPart(List cuboids, String name) { this.name = name; - { - int vertices = 0; - for (PartBuilder.CuboidBuilder cuboid : cuboids) { - vertices += cuboid.vertices(); - } - this.vertices = vertices; + this.vertexCount = countVertices(cuboids); + + contents = MemoryBlock.malloc(size()); + long ptr = contents.ptr(); + VertexWriter writer = new VertexWriterImpl(ptr); + for (PartBuilder.CuboidBuilder cuboid : cuboids) { + cuboid.write(writer); } - try (var stack = MemoryStack.stackPush()) { - PosTexNormalWriterUnsafe writer = getVertexType().createWriter(stack.malloc(size())); - for (PartBuilder.CuboidBuilder cuboid : cuboids) { - cuboid.buffer(writer); - } + vertexList = getVertexType().createVertexList(); + vertexList.ptr(ptr); + vertexList.setVertexCount(vertexCount); - reader = writer.intoReader(this.vertices); - } - - boundingSphere = ModelUtil.computeBoundingSphere(reader); + boundingSphere = ModelUtil.computeBoundingSphere(vertexList); } public static PartBuilder builder(String name, int sizeU, int sizeV) { return new PartBuilder(name, sizeU, sizeV); } - @Override - public String name() { - return name; - } - - @Override - public int getVertexCount() { - return vertices; - } - - @Override - public VertexList getReader() { - return reader; - } - @Override public PosTexNormalVertex getVertexType() { return Formats.POS_TEX_NORMAL; } + @Override + public int getVertexCount() { + return vertexCount; + } + + @Override + public void write(long ptr) { + contents.copyTo(ptr); + } + + @Override + public void write(MutableVertexList dst) { + vertexList.writeAll(dst); + } + + @Override + public void close() { + contents.free(); + } + + @Override + public String name() { + return name; + } + @Override public Vector4fc getBoundingSphere() { return boundingSphere; } + + private static int countVertices(List cuboids) { + int vertices = 0; + for (PartBuilder.CuboidBuilder cuboid : cuboids) { + vertices += cuboid.vertices(); + } + return vertices; + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/hardcoded/PartBuilder.java b/src/main/java/com/jozufozu/flywheel/core/hardcoded/PartBuilder.java index 3747fbe62..945607a47 100644 --- a/src/main/java/com/jozufozu/flywheel/core/hardcoded/PartBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/core/hardcoded/PartBuilder.java @@ -5,7 +5,6 @@ import java.util.EnumSet; import java.util.List; import java.util.Set; -import com.jozufozu.flywheel.core.vertex.PosTexNormalWriterUnsafe; import com.mojang.math.Matrix3f; import com.mojang.math.Quaternion; import com.mojang.math.Vector3f; @@ -160,8 +159,7 @@ public class PartBuilder { return visibleFaces.size() * 4; } - public void buffer(PosTexNormalWriterUnsafe buffer) { - + public void write(VertexWriter writer) { float sizeX = posX2 - posX1; float sizeY = posY2 - posY1; float sizeZ = posZ2 - posZ1; @@ -219,28 +217,27 @@ public class PartBuilder { float f12 = getV((float)textureOffsetV + sizeZ + sizeY); if (invertYZ) { - quad(buffer, new Vector3f[]{hlh, llh, lll, hll}, f6, f11, f7, f10, down); - quad(buffer, new Vector3f[]{hhl, lhl, lhh, hhh}, f5, f10, f6, f11, up); - quad(buffer, new Vector3f[]{lll, llh, lhh, lhl}, f5, f12, f4, f11, west); - quad(buffer, new Vector3f[]{hll, lll, lhl, hhl}, f9, f12, f8, f11, north); - quad(buffer, new Vector3f[]{hlh, hll, hhl, hhh}, f8, f12, f6, f11, east); - quad(buffer, new Vector3f[]{llh, hlh, hhh, lhh}, f6, f12, f5, f11, south); + quad(writer, new Vector3f[]{hlh, llh, lll, hll}, f6, f11, f7, f10, down); + quad(writer, new Vector3f[]{hhl, lhl, lhh, hhh}, f5, f10, f6, f11, up); + quad(writer, new Vector3f[]{lll, llh, lhh, lhl}, f5, f12, f4, f11, west); + quad(writer, new Vector3f[]{hll, lll, lhl, hhl}, f9, f12, f8, f11, north); + quad(writer, new Vector3f[]{hlh, hll, hhl, hhh}, f8, f12, f6, f11, east); + quad(writer, new Vector3f[]{llh, hlh, hhh, lhh}, f6, f12, f5, f11, south); } else { - quad(buffer, new Vector3f[]{hlh, llh, lll, hll}, f5, f10, f6, f11, down); - quad(buffer, new Vector3f[]{hhl, lhl, lhh, hhh}, f6, f11, f7, f10, up); - quad(buffer, new Vector3f[]{lll, llh, lhh, lhl}, f4, f11, f5, f12, west); - quad(buffer, new Vector3f[]{hll, lll, lhl, hhl}, f5, f11, f6, f12, north); - quad(buffer, new Vector3f[]{hlh, hll, hhl, hhh}, f6, f11, f8, f12, east); - quad(buffer, new Vector3f[]{llh, hlh, hhh, lhh}, f8, f11, f9, f12, south); + quad(writer, new Vector3f[]{hlh, llh, lll, hll}, f5, f10, f6, f11, down); + quad(writer, new Vector3f[]{hhl, lhl, lhh, hhh}, f6, f11, f7, f10, up); + quad(writer, new Vector3f[]{lll, llh, lhh, lhl}, f4, f11, f5, f12, west); + quad(writer, new Vector3f[]{hll, lll, lhl, hhl}, f5, f11, f6, f12, north); + quad(writer, new Vector3f[]{hlh, hll, hhl, hhh}, f6, f11, f8, f12, east); + quad(writer, new Vector3f[]{llh, hlh, hhh, lhh}, f8, f11, f9, f12, south); } } - public void quad(PosTexNormalWriterUnsafe buffer, Vector3f[] vertices, float minU, float minV, float maxU, float maxV, Vector3f normal) { - buffer.putVertex(vertices[0].x(), vertices[0].y(), vertices[0].z(), normal.x(), normal.y(), normal.z(), maxU, minV); - buffer.putVertex(vertices[1].x(), vertices[1].y(), vertices[1].z(), normal.x(), normal.y(), normal.z(), minU, minV); - buffer.putVertex(vertices[2].x(), vertices[2].y(), vertices[2].z(), normal.x(), normal.y(), normal.z(), minU, maxV); - buffer.putVertex(vertices[3].x(), vertices[3].y(), vertices[3].z(), normal.x(), normal.y(), normal.z(), maxU, maxV); - + public void quad(VertexWriter writer, Vector3f[] vertices, float minU, float minV, float maxU, float maxV, Vector3f normal) { + writer.putVertex(vertices[0].x(), vertices[0].y(), vertices[0].z(), maxU, minV, normal.x(), normal.y(), normal.z()); + writer.putVertex(vertices[1].x(), vertices[1].y(), vertices[1].z(), minU, minV, normal.x(), normal.y(), normal.z()); + writer.putVertex(vertices[2].x(), vertices[2].y(), vertices[2].z(), minU, maxV, normal.x(), normal.y(), normal.z()); + writer.putVertex(vertices[3].x(), vertices[3].y(), vertices[3].z(), maxU, maxV, normal.x(), normal.y(), normal.z()); } public float getU(float u) { @@ -258,5 +255,4 @@ public class PartBuilder { } } - } diff --git a/src/main/java/com/jozufozu/flywheel/core/hardcoded/VertexWriter.java b/src/main/java/com/jozufozu/flywheel/core/hardcoded/VertexWriter.java new file mode 100644 index 000000000..7e031c58b --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/hardcoded/VertexWriter.java @@ -0,0 +1,5 @@ +package com.jozufozu.flywheel.core.hardcoded; + +public interface VertexWriter { + void putVertex(float x, float y, float z, float u, float v, float nX, float nY, float nZ); +} diff --git a/src/main/java/com/jozufozu/flywheel/core/hardcoded/VertexWriterImpl.java b/src/main/java/com/jozufozu/flywheel/core/hardcoded/VertexWriterImpl.java new file mode 100644 index 000000000..3b8b617cd --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/hardcoded/VertexWriterImpl.java @@ -0,0 +1,27 @@ +package com.jozufozu.flywheel.core.hardcoded; + +import org.lwjgl.system.MemoryUtil; + +import com.jozufozu.flywheel.util.RenderMath; + +public class VertexWriterImpl implements VertexWriter { + private long ptr; + + public VertexWriterImpl(long ptr) { + this.ptr = ptr; + } + + @Override + public void putVertex(float x, float y, float z, float u, float v, float nX, float nY, float nZ) { + MemoryUtil.memPutFloat(ptr, x); + MemoryUtil.memPutFloat(ptr + 4, y); + MemoryUtil.memPutFloat(ptr + 8, z); + MemoryUtil.memPutFloat(ptr + 12, u); + MemoryUtil.memPutFloat(ptr + 16, v); + MemoryUtil.memPutByte(ptr + 20, RenderMath.nb(nX)); + MemoryUtil.memPutByte(ptr + 21, RenderMath.nb(nY)); + MemoryUtil.memPutByte(ptr + 22, RenderMath.nb(nZ)); + + ptr += 23; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/layout/CommonItems.java b/src/main/java/com/jozufozu/flywheel/core/layout/CommonItems.java index e8d51f557..488d16489 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/CommonItems.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/CommonItems.java @@ -1,26 +1,39 @@ package com.jozufozu.flywheel.core.layout; import com.jozufozu.flywheel.backend.gl.GlNumericType; +import com.jozufozu.flywheel.backend.gl.array.VertexAttributeF; import com.jozufozu.flywheel.backend.gl.array.VertexAttributeI; public class CommonItems { - public static final PrimitiveItem VEC4 = new PrimitiveItem(GlNumericType.FLOAT, 4); - public static final PrimitiveItem VEC3 = new PrimitiveItem(GlNumericType.FLOAT, 3); - public static final PrimitiveItem VEC2 = new PrimitiveItem(GlNumericType.FLOAT, 2); - public static final PrimitiveItem FLOAT = new PrimitiveItem(GlNumericType.FLOAT, 1); + public static final PrimitiveItem VEC4 = primitiveF(GlNumericType.FLOAT, 4); + public static final PrimitiveItem VEC3 = primitiveF(GlNumericType.FLOAT, 3); + public static final PrimitiveItem VEC2 = primitiveF(GlNumericType.FLOAT, 2); + public static final PrimitiveItem FLOAT = primitiveF(GlNumericType.FLOAT, 1); - public static final PrimitiveItem QUATERNION = new PrimitiveItem(GlNumericType.FLOAT, 4); - public static final PrimitiveItem NORMAL = new PrimitiveItem(GlNumericType.BYTE, 3, true); - public static final PrimitiveItem UV = new PrimitiveItem(GlNumericType.FLOAT, 2); + public static final PrimitiveItem QUATERNION = primitiveF(GlNumericType.FLOAT, 4); + public static final PrimitiveItem NORMAL = primitiveF(GlNumericType.BYTE, 3, true); + public static final PrimitiveItem UV = primitiveF(GlNumericType.FLOAT, 2); - public static final PrimitiveItem RGBA = new PrimitiveItem(GlNumericType.UBYTE, 4, true); - public static final PrimitiveItem RGB = new PrimitiveItem(GlNumericType.UBYTE, 3, true); - public static final PrimitiveItem LIGHT = new PrimitiveItem(new VertexAttributeI(GlNumericType.UBYTE, 2)); - public static final PrimitiveItem LIGHT_SHORT = new PrimitiveItem(new VertexAttributeI(GlNumericType.USHORT, 2)); + public static final PrimitiveItem RGBA = primitiveF(GlNumericType.UBYTE, 4, true); + public static final PrimitiveItem RGB = primitiveF(GlNumericType.UBYTE, 3, true); + public static final PrimitiveItem LIGHT = primitiveI(GlNumericType.UBYTE, 2); + public static final PrimitiveItem LIGHT_SHORT = primitiveI(GlNumericType.USHORT, 2); - public static final PrimitiveItem NORMALIZED_BYTE = new PrimitiveItem(GlNumericType.BYTE, 1, true); + public static final PrimitiveItem NORMALIZED_BYTE = primitiveF(GlNumericType.BYTE, 1, true); public static final MatrixItem MAT3 = new MatrixItem(3, 3); public static final MatrixItem MAT4 = new MatrixItem(4, 4); + + private static PrimitiveItem primitiveF(GlNumericType type, int count, boolean normalized) { + return new PrimitiveItem(new VertexAttributeF(type, count, normalized)); + } + + private static PrimitiveItem primitiveF(GlNumericType type, int count) { + return primitiveF(type, count, false); + } + + private static PrimitiveItem primitiveI(GlNumericType type, int count) { + return new PrimitiveItem(new VertexAttributeI(type, count)); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/layout/PrimitiveItem.java b/src/main/java/com/jozufozu/flywheel/core/layout/PrimitiveItem.java index bc6423e17..d26fc4a16 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/PrimitiveItem.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/PrimitiveItem.java @@ -2,22 +2,12 @@ package com.jozufozu.flywheel.core.layout; import java.util.function.Consumer; -import com.jozufozu.flywheel.backend.gl.GlNumericType; import com.jozufozu.flywheel.backend.gl.array.VertexAttribute; -import com.jozufozu.flywheel.backend.gl.array.VertexAttributeF; public class PrimitiveItem implements LayoutItem { private final VertexAttribute attribute; - public PrimitiveItem(GlNumericType type, int count) { - this(type, count, false); - } - - public PrimitiveItem(GlNumericType type, int count, boolean normalized) { - this(new VertexAttributeF(type, count, normalized)); - } - public PrimitiveItem(VertexAttribute attribute) { this.attribute = attribute; } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java b/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java index dcc7ffa8f..9a120f6b6 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java @@ -1,71 +1,56 @@ package com.jozufozu.flywheel.core.model; -import java.nio.ByteBuffer; - -import com.jozufozu.flywheel.api.vertex.VertexList; +import com.jozufozu.flywheel.api.vertex.MutableVertexList; import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.api.vertex.VertexWriter; import com.jozufozu.flywheel.backend.instancing.instancing.ElementBuffer; import com.jozufozu.flywheel.core.QuadConverter; import com.jozufozu.flywheel.util.joml.Vector4fc; /** - * A mesh that can be rendered by flywheel. - * - *

- * It is expected that the following assertion will not fail: - *

- * - *
{@code
- * Mesh mesh = ...;
- * VecBuffer into = ...;
- *
- * int initial = VecBuffer.unwrap().position();
- *
- * mesh.buffer(into);
- *
- * int final = VecBuffer.unwrap().position();
- *
- * assert mesh.size() == final - initial;
- * }
+ * A holder for arbitrary vertex data that can be written to memory or a vertex list. */ public interface Mesh { - /** - * A name uniquely identifying this model. - */ - String name(); - VertexType getVertexType(); - VertexList getReader(); - Vector4fc getBoundingSphere(); /** - * @return The number of vertices the model has. + * @return The number of vertices this mesh has. */ - default int getVertexCount() { - return getReader().getVertexCount(); - } + int getVertexCount(); /** * Is there nothing to render? * @return true if there are no vertices. */ default boolean isEmpty() { - return getReader().isEmpty(); + return getVertexCount() == 0; } /** - * The size in bytes that this model's data takes up. + * The size in bytes that this mesh's data takes up. */ default int size() { return getVertexType().byteOffset(getVertexCount()); } /** - * Create an element buffer object that indexes the vertices of this model. + * Write this mesh into memory. The written data will use the format defined by {@link #getVertexType()} and the amount of + * bytes written will be the same as the return value of {@link #size()}. + * @param ptr The address to which data is written to. + */ + void write(long ptr); + + /** + * Write this mesh into a vertex list. Vertices with index {@literal <}0 or {@literal >=}{@link #getVertexCount()} will not be + * modified. + * @param vertexList The vertex list to which data is written to. + */ + void write(MutableVertexList vertexList); + + /** + * Create an element buffer object that indexes the vertices of this mesh. * *

* Very often models in minecraft are made up of sequential quads, which is a very predictable pattern. @@ -79,9 +64,10 @@ public interface Mesh { .quads2Tris(getVertexCount() / 4); } - default void writeInto(ByteBuffer buffer, long byteIndex) { - VertexWriter writer = getVertexType().createWriter(buffer); - writer.seek(byteIndex); - writer.writeVertexList(getReader()); - } + void close(); + + /** + * A name uniquely identifying this mesh. + */ + String name(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/Model.java b/src/main/java/com/jozufozu/flywheel/core/model/Model.java index e0d247387..092c4a3cd 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/Model.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/Model.java @@ -7,6 +7,8 @@ import com.jozufozu.flywheel.api.material.Material; public interface Model { Map getMeshes(); + void delete(); + default int getVertexCount() { int size = 0; for (Mesh mesh : getMeshes().values()) { diff --git a/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java b/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java index fe3041287..103f05634 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java @@ -5,16 +5,23 @@ import java.nio.ByteBuffer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.lwjgl.system.MemoryUtil; import com.dreizak.miniball.highdim.Miniball; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.api.vertex.ReusableVertexList; import com.jozufozu.flywheel.api.vertex.VertexList; +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.backend.memory.MemoryBlock; import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.vertex.Formats; import com.jozufozu.flywheel.util.joml.Vector4f; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.jozufozu.flywheel.core.vertex.VertexListProviderRegistry; +import com.mojang.blaze3d.vertex.BufferBuilder.DrawState; +import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.datafixers.util.Pair; import net.minecraft.client.Minecraft; @@ -46,15 +53,27 @@ public class ModelUtil { return dispatcher; } - public static VertexList createVertexList(BufferBuilder bufferBuilder) { - Pair pair = bufferBuilder.popNextBuffer(); - BufferBuilder.DrawState drawState = pair.getFirst(); + public static Pair convertBlockBuffer(Pair pair) { + DrawState drawState = pair.getFirst(); + int vertexCount = drawState.vertexCount(); + VertexFormat srcFormat = drawState.format(); + VertexType dstVertexType = Formats.BLOCK; - if (drawState.format() != DefaultVertexFormat.BLOCK) { - throw new RuntimeException("Cannot use BufferBuilder with " + drawState.format()); - } + ByteBuffer src = pair.getSecond(); + MemoryBlock dst = MemoryBlock.malloc(src.capacity()); + long srcPtr = MemoryUtil.memAddress(src); + long dstPtr = dst.ptr(); - return Formats.BLOCK.createReader(pair.getSecond(), drawState.vertexCount()); + ReusableVertexList srcList = VertexListProviderRegistry.getOrInfer(srcFormat).createVertexList(); + ReusableVertexList dstList = dstVertexType.createVertexList(); + srcList.ptr(srcPtr); + dstList.ptr(dstPtr); + srcList.setVertexCount(vertexCount); + dstList.setVertexCount(vertexCount); + + srcList.writeAll(dstList); + + return Pair.of(dstVertexType, dst); } @Nullable diff --git a/src/main/java/com/jozufozu/flywheel/core/model/Models.java b/src/main/java/com/jozufozu/flywheel/core/model/Models.java index 4891a3cd6..d327abc34 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/Models.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/Models.java @@ -1,5 +1,6 @@ package com.jozufozu.flywheel.core.model; +import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -41,8 +42,16 @@ public class Models { } public static void onReload(ReloadRenderersEvent event) { + deleteAll(BLOCK_STATE.values()); + deleteAll(PARTIAL.values()); + deleteAll(PARTIAL_DIR.values()); + BLOCK_STATE.clear(); PARTIAL.clear(); PARTIAL_DIR.clear(); } + + private static void deleteAll(Collection values) { + values.forEach(Model::delete); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/SimpleLazyModel.java b/src/main/java/com/jozufozu/flywheel/core/model/SimpleLazyModel.java index 7933854d2..3af609e4f 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/SimpleLazyModel.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/SimpleLazyModel.java @@ -28,6 +28,11 @@ public class SimpleLazyModel implements Model { return ImmutableMap.of(material, supplier.get()); } + @Override + public void delete() { + supplier.ifPresent(Mesh::close); + } + public int getVertexCount() { return supplier.map(Mesh::getVertexCount) .orElse(0); diff --git a/src/main/java/com/jozufozu/flywheel/core/model/SimpleMesh.java b/src/main/java/com/jozufozu/flywheel/core/model/SimpleMesh.java index e5808067f..95ce7d8bf 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/SimpleMesh.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/SimpleMesh.java @@ -1,27 +1,37 @@ package com.jozufozu.flywheel.core.model; -import com.jozufozu.flywheel.api.vertex.VertexList; +import com.jozufozu.flywheel.api.vertex.MutableVertexList; +import com.jozufozu.flywheel.api.vertex.ReusableVertexList; import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.backend.memory.MemoryBlock; import com.jozufozu.flywheel.util.joml.Vector4f; import com.jozufozu.flywheel.util.joml.Vector4fc; public class SimpleMesh implements Mesh { - private final VertexList reader; private final VertexType vertexType; + private final int vertexCount; + private final MemoryBlock contents; + private final ReusableVertexList vertexList; private final String name; private final Vector4f boundingSphere; - public SimpleMesh(VertexList reader, VertexType vertexType, String name) { - this.reader = reader; + public SimpleMesh(VertexType vertexType, MemoryBlock contents, String name) { this.vertexType = vertexType; + this.contents = contents; this.name = name; - boundingSphere = ModelUtil.computeBoundingSphere(reader); - } + int bytes = (int) contents.size(); + int stride = vertexType.getStride(); + if (bytes % stride != 0) { + throw new IllegalArgumentException("MemoryBlock contains non-whole amount of vertices!"); + } + vertexCount = bytes / stride; - @Override - public String name() { - return name; + vertexList = getVertexType().createVertexList(); + vertexList.ptr(contents.ptr()); + vertexList.setVertexCount(vertexCount); + + boundingSphere = ModelUtil.computeBoundingSphere(vertexList); } @Override @@ -30,8 +40,28 @@ public class SimpleMesh implements Mesh { } @Override - public VertexList getReader() { - return reader; + public int getVertexCount() { + return vertexCount; + } + + @Override + public void write(long ptr) { + contents.copyTo(ptr); + } + + @Override + public void write(MutableVertexList dst) { + vertexList.writeAll(dst); + } + + @Override + public void close() { + contents.free(); + } + + @Override + public String name() { + return name; } @Override diff --git a/src/main/java/com/jozufozu/flywheel/core/model/TessellatedModel.java b/src/main/java/com/jozufozu/flywheel/core/model/TessellatedModel.java index 0f987bb71..d1986dc6e 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/TessellatedModel.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/TessellatedModel.java @@ -19,6 +19,12 @@ public class TessellatedModel implements Model { return meshes; } + @Override + public void delete() { + meshes.values() + .forEach(Mesh::close); + } + public boolean isShadeSeparated() { return shadeSeparated; } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/buffering/BakedModelBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/buffering/BakedModelBuilder.java index 7393ac14b..b86ec43f7 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/buffering/BakedModelBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/buffering/BakedModelBuilder.java @@ -4,6 +4,8 @@ import java.util.function.BiFunction; import com.google.common.collect.ImmutableMap; import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.backend.memory.MemoryBlock; import com.jozufozu.flywheel.core.model.Mesh; import com.jozufozu.flywheel.core.model.ModelUtil; import com.jozufozu.flywheel.core.model.SimpleMesh; @@ -12,13 +14,13 @@ import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.BufferFacto import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ResultConsumer; import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ShadeSeparatedBufferFactory; import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ShadeSeparatedResultConsumer; -import com.jozufozu.flywheel.core.vertex.Formats; import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter; import com.jozufozu.flywheel.core.virtual.VirtualEmptyModelData; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.datafixers.util.Pair; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.resources.model.BakedModel; @@ -28,9 +30,10 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.client.model.data.IModelData; public class BakedModelBuilder { + private static final int STARTING_CAPACITY = 64; + private final BakedModel bakedModel; private boolean shadeSeparated = true; - private VertexFormat vertexFormat; private BlockAndTintGetter renderWorld; private BlockState blockState; private PoseStack poseStack; @@ -46,11 +49,6 @@ public class BakedModelBuilder { return this; } - public BakedModelBuilder vertexFormat(VertexFormat vertexFormat) { - this.vertexFormat = vertexFormat; - return this; - } - public BakedModelBuilder renderWorld(BlockAndTintGetter renderWorld) { this.renderWorld = renderWorld; return this; @@ -80,9 +78,6 @@ public class BakedModelBuilder { public TessellatedModel build() { ModelBufferingObjects objects = ModelBufferingObjects.THREAD_LOCAL.get(); - if (vertexFormat == null) { - vertexFormat = DefaultVertexFormat.BLOCK; - } if (renderWorld == null) { renderWorld = VirtualEmptyBlockGetter.INSTANCE; } @@ -103,29 +98,31 @@ public class BakedModelBuilder { if (shadeSeparated) { ShadeSeparatedBufferFactory bufferFactory = (renderType, shaded) -> { - BufferBuilder buffer = new BufferBuilder(64); - buffer.begin(VertexFormat.Mode.QUADS, vertexFormat); + BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY); + buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); return buffer; }; ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, buffer) -> { buffer.end(); Material material = materialFunc.apply(renderType, shaded); if (material != null) { - meshMapBuilder.put(material, new SimpleMesh(ModelUtil.createVertexList(buffer), Formats.BLOCK, "bakedModel=" + bakedModel.toString() + ",renderType=" + renderType.toString() + ",shaded=" + shaded)); + Pair pair = ModelUtil.convertBlockBuffer(buffer.popNextBuffer()); + meshMapBuilder.put(material, new SimpleMesh(pair.getFirst(), pair.getSecond(), "bakedModel=" + bakedModel.toString() + ",renderType=" + renderType.toString() + ",shaded=" + shaded)); } }; ModelBufferingUtil.bufferSingleShadeSeparated(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, bufferFactory, objects.shadeSeparatingBufferWrapper, objects.random, modelData, resultConsumer); } else { BufferFactory bufferFactory = (renderType) -> { - BufferBuilder buffer = new BufferBuilder(64); - buffer.begin(VertexFormat.Mode.QUADS, vertexFormat); + BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY); + buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); return buffer; }; ResultConsumer resultConsumer = (renderType, buffer) -> { buffer.end(); Material material = materialFunc.apply(renderType, false); if (material != null) { - meshMapBuilder.put(material, new SimpleMesh(ModelUtil.createVertexList(buffer), Formats.BLOCK, "bakedModel=" + bakedModel.toString() + ",renderType=" + renderType.toString())); + Pair pair = ModelUtil.convertBlockBuffer(buffer.popNextBuffer()); + meshMapBuilder.put(material, new SimpleMesh(pair.getFirst(), pair.getSecond(), "bakedModel=" + bakedModel.toString() + ",renderType=" + renderType.toString())); } }; ModelBufferingUtil.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, bufferFactory, objects.bufferWrapper, objects.random, modelData, resultConsumer); diff --git a/src/main/java/com/jozufozu/flywheel/core/model/buffering/BlockModelBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/buffering/BlockModelBuilder.java index 022e948b9..b69549c6c 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/buffering/BlockModelBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/buffering/BlockModelBuilder.java @@ -4,6 +4,8 @@ import java.util.function.BiFunction; import com.google.common.collect.ImmutableMap; import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.backend.memory.MemoryBlock; import com.jozufozu.flywheel.core.model.Mesh; import com.jozufozu.flywheel.core.model.ModelUtil; import com.jozufozu.flywheel.core.model.SimpleMesh; @@ -12,13 +14,13 @@ import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.BufferFacto import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ResultConsumer; import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ShadeSeparatedBufferFactory; import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ShadeSeparatedResultConsumer; -import com.jozufozu.flywheel.core.vertex.Formats; import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter; import com.jozufozu.flywheel.core.virtual.VirtualEmptyModelData; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.datafixers.util.Pair; import net.minecraft.client.renderer.RenderType; import net.minecraft.world.level.BlockAndTintGetter; @@ -26,9 +28,10 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.client.model.data.IModelData; public class BlockModelBuilder { + private static final int STARTING_CAPACITY = 64; + private final BlockState state; private boolean shadeSeparated = true; - private VertexFormat vertexFormat; private BlockAndTintGetter renderWorld; private PoseStack poseStack; private IModelData modelData; @@ -43,11 +46,6 @@ public class BlockModelBuilder { return this; } - public BlockModelBuilder vertexFormat(VertexFormat vertexFormat) { - this.vertexFormat = vertexFormat; - return this; - } - public BlockModelBuilder renderWorld(BlockAndTintGetter renderWorld) { this.renderWorld = renderWorld; return this; @@ -72,9 +70,6 @@ public class BlockModelBuilder { public TessellatedModel build() { ModelBufferingObjects objects = ModelBufferingObjects.THREAD_LOCAL.get(); - if (vertexFormat == null) { - vertexFormat = DefaultVertexFormat.BLOCK; - } if (renderWorld == null) { renderWorld = VirtualEmptyBlockGetter.INSTANCE; } @@ -92,29 +87,31 @@ public class BlockModelBuilder { if (shadeSeparated) { ShadeSeparatedBufferFactory bufferFactory = (renderType, shaded) -> { - BufferBuilder buffer = new BufferBuilder(64); - buffer.begin(VertexFormat.Mode.QUADS, vertexFormat); + BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY); + buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); return buffer; }; ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, buffer) -> { buffer.end(); Material material = materialFunc.apply(renderType, shaded); if (material != null) { - meshMapBuilder.put(material, new SimpleMesh(ModelUtil.createVertexList(buffer), Formats.BLOCK, "state=" + state.toString() + ",renderType=" + renderType.toString() + ",shaded=" + shaded)); + Pair pair = ModelUtil.convertBlockBuffer(buffer.popNextBuffer()); + meshMapBuilder.put(material, new SimpleMesh(pair.getFirst(), pair.getSecond(), "state=" + state.toString() + ",renderType=" + renderType.toString() + ",shaded=" + shaded)); } }; ModelBufferingUtil.bufferBlockShadeSeparated(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, bufferFactory, objects.shadeSeparatingBufferWrapper, objects.random, modelData, resultConsumer); } else { BufferFactory bufferFactory = (renderType) -> { - BufferBuilder buffer = new BufferBuilder(64); - buffer.begin(VertexFormat.Mode.QUADS, vertexFormat); + BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY); + buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); return buffer; }; ResultConsumer resultConsumer = (renderType, buffer) -> { buffer.end(); Material material = materialFunc.apply(renderType, false); if (material != null) { - meshMapBuilder.put(material, new SimpleMesh(ModelUtil.createVertexList(buffer), Formats.BLOCK, "state=" + state.toString() + ",renderType=" + renderType.toString())); + Pair pair = ModelUtil.convertBlockBuffer(buffer.popNextBuffer()); + meshMapBuilder.put(material, new SimpleMesh(pair.getFirst(), pair.getSecond(), "state=" + state.toString() + ",renderType=" + renderType.toString())); } }; ModelBufferingUtil.bufferBlock(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, bufferFactory, objects.bufferWrapper, objects.random, modelData, resultConsumer); diff --git a/src/main/java/com/jozufozu/flywheel/core/model/buffering/MultiBlockModelBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/buffering/MultiBlockModelBuilder.java index 33acbcdab..dd0342e5f 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/buffering/MultiBlockModelBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/buffering/MultiBlockModelBuilder.java @@ -7,6 +7,8 @@ import java.util.function.BiFunction; import com.google.common.collect.ImmutableMap; import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.backend.memory.MemoryBlock; import com.jozufozu.flywheel.core.model.Mesh; import com.jozufozu.flywheel.core.model.ModelUtil; import com.jozufozu.flywheel.core.model.SimpleMesh; @@ -15,12 +17,12 @@ import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.BufferFacto import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ResultConsumer; import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ShadeSeparatedBufferFactory; import com.jozufozu.flywheel.core.model.buffering.ModelBufferingUtil.ShadeSeparatedResultConsumer; -import com.jozufozu.flywheel.core.vertex.Formats; import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.datafixers.util.Pair; import net.minecraft.client.renderer.RenderType; import net.minecraft.core.BlockPos; @@ -29,6 +31,8 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp import net.minecraftforge.client.model.data.IModelData; public class MultiBlockModelBuilder { + private static final int STARTING_CAPACITY = 1024; + private final Collection blocks; private boolean shadeSeparated = true; private VertexFormat vertexFormat; @@ -46,11 +50,6 @@ public class MultiBlockModelBuilder { return this; } - public MultiBlockModelBuilder vertexFormat(VertexFormat vertexFormat) { - this.vertexFormat = vertexFormat; - return this; - } - public MultiBlockModelBuilder renderWorld(BlockAndTintGetter renderWorld) { this.renderWorld = renderWorld; return this; @@ -95,29 +94,31 @@ public class MultiBlockModelBuilder { if (shadeSeparated) { ShadeSeparatedBufferFactory bufferFactory = (renderType, shaded) -> { - BufferBuilder buffer = new BufferBuilder(1024); - buffer.begin(VertexFormat.Mode.QUADS, vertexFormat); + BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY); + buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); return buffer; }; ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, buffer) -> { buffer.end(); Material material = materialFunc.apply(renderType, shaded); if (material != null) { - meshMapBuilder.put(material, new SimpleMesh(ModelUtil.createVertexList(buffer), Formats.BLOCK, "renderType=" + renderType.toString() + ",shaded=" + shaded)); + Pair pair = ModelUtil.convertBlockBuffer(buffer.popNextBuffer()); + meshMapBuilder.put(material, new SimpleMesh(pair.getFirst(), pair.getSecond(), "renderType=" + renderType.toString() + ",shaded=" + shaded)); } }; ModelBufferingUtil.bufferMultiBlockShadeSeparated(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, bufferFactory, objects.shadeSeparatingBufferWrapper, objects.random, modelDataMap, resultConsumer); } else { BufferFactory bufferFactory = (renderType) -> { - BufferBuilder buffer = new BufferBuilder(1024); - buffer.begin(VertexFormat.Mode.QUADS, vertexFormat); + BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY); + buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); return buffer; }; ResultConsumer resultConsumer = (renderType, buffer) -> { buffer.end(); Material material = materialFunc.apply(renderType, false); if (material != null) { - meshMapBuilder.put(material, new SimpleMesh(ModelUtil.createVertexList(buffer), Formats.BLOCK, "renderType=" + renderType.toString())); + Pair pair = ModelUtil.convertBlockBuffer(buffer.popNextBuffer()); + meshMapBuilder.put(material, new SimpleMesh(pair.getFirst(), pair.getSecond(), "renderType=" + renderType.toString())); } }; ModelBufferingUtil.bufferMultiBlock(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, bufferFactory, objects.bufferWrapper, objects.random, modelDataMap, resultConsumer); diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/ColoredLitWriter.java b/src/main/java/com/jozufozu/flywheel/core/structs/ColoredLitWriter.java new file mode 100644 index 000000000..dcd23aca0 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/structs/ColoredLitWriter.java @@ -0,0 +1,17 @@ +package com.jozufozu.flywheel.core.structs; + +import org.lwjgl.system.MemoryUtil; + +import com.jozufozu.flywheel.api.struct.StructWriter; + +public abstract class ColoredLitWriter implements StructWriter { + @Override + public void write(long ptr, D d) { + MemoryUtil.memPutByte(ptr, d.blockLight); + MemoryUtil.memPutByte(ptr + 1, d.skyLight); + MemoryUtil.memPutByte(ptr + 2, d.r); + MemoryUtil.memPutByte(ptr + 3, d.g); + MemoryUtil.memPutByte(ptr + 4, d.b); + MemoryUtil.memPutByte(ptr + 5, d.a); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/ColoredLitWriterUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/structs/ColoredLitWriterUnsafe.java deleted file mode 100644 index 985fc7046..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/structs/ColoredLitWriterUnsafe.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.jozufozu.flywheel.core.structs; - -import java.nio.ByteBuffer; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.backend.struct.UnsafeBufferWriter; - -public abstract class ColoredLitWriterUnsafe extends UnsafeBufferWriter { - - public ColoredLitWriterUnsafe(StructType structType, ByteBuffer byteBuffer) { - super(structType, byteBuffer); - } - - @Override - protected void writeInternal(D d) { - long ptr = writePointer; - MemoryUtil.memPutByte(ptr, d.blockLight); - MemoryUtil.memPutByte(ptr + 1, d.skyLight); - MemoryUtil.memPutByte(ptr + 2, d.r); - MemoryUtil.memPutByte(ptr + 3, d.g); - MemoryUtil.memPutByte(ptr + 4, d.b); - MemoryUtil.memPutByte(ptr + 5, d.a); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/StructTypes.java b/src/main/java/com/jozufozu/flywheel/core/structs/StructTypes.java index 96015bf27..597a2a43c 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/StructTypes.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/StructTypes.java @@ -2,10 +2,10 @@ package com.jozufozu.flywheel.core.structs; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.core.ComponentRegistry; -import com.jozufozu.flywheel.core.structs.model.TransformedPart; -import com.jozufozu.flywheel.core.structs.model.TransformedType; import com.jozufozu.flywheel.core.structs.oriented.OrientedPart; import com.jozufozu.flywheel.core.structs.oriented.OrientedType; +import com.jozufozu.flywheel.core.structs.transformed.TransformedPart; +import com.jozufozu.flywheel.core.structs.transformed.TransformedType; public class StructTypes { public static final StructType TRANSFORMED = ComponentRegistry.register(new TransformedType()); diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedWriterUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedWriterUnsafe.java deleted file mode 100644 index 9aab8c48b..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedWriterUnsafe.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.jozufozu.flywheel.core.structs.model; - -import java.nio.ByteBuffer; - -import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.core.structs.ColoredLitWriterUnsafe; -import com.jozufozu.flywheel.util.extension.MatrixExtension; - -public class TransformedWriterUnsafe extends ColoredLitWriterUnsafe { - - public TransformedWriterUnsafe(StructType structType, ByteBuffer byteBuffer) { - super(structType, byteBuffer); - } - - @Override - protected void writeInternal(TransformedPart d) { - super.writeInternal(d); - long ptr = writePointer + 6; - - ((MatrixExtension) (Object) d.model).flywheel$writeUnsafe(ptr); - ((MatrixExtension) (Object) d.normal).flywheel$writeUnsafe(ptr + 4 * 16); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/model/package-info.java b/src/main/java/com/jozufozu/flywheel/core/structs/model/package-info.java deleted file mode 100644 index 759c3a038..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/structs/model/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -package com.jozufozu.flywheel.core.structs.model; - -import javax.annotation.ParametersAreNonnullByDefault; - -import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java index 5bf956fa1..039fdd1e5 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java @@ -1,8 +1,5 @@ package com.jozufozu.flywheel.core.structs.oriented; -import java.nio.ByteBuffer; - -import com.jozufozu.flywheel.api.struct.StorageBufferWriter; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructWriter; import com.jozufozu.flywheel.core.Components; @@ -33,8 +30,8 @@ public class OrientedType implements StructType { } @Override - public StructWriter getWriter(ByteBuffer backing) { - return new OrientedWriterUnsafe(this, backing); + public StructWriter getWriter() { + return OrientedWriter.INSTANCE; } @Override @@ -53,7 +50,7 @@ public class OrientedType implements StructType { } @Override - public VertexTransformer getVertexTransformer() { + public VertexTransformer getVertexTransformer() { return (vertexList, struct, level) -> { Vector4f pos = new Vector4f(); Vector3f normal = new Vector3f(); diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedWriterUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedWriter.java similarity index 54% rename from src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedWriterUnsafe.java rename to src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedWriter.java index fb03c4d1e..8aa99cef4 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedWriterUnsafe.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedWriter.java @@ -1,21 +1,15 @@ package com.jozufozu.flywheel.core.structs.oriented; -import java.nio.ByteBuffer; - import org.lwjgl.system.MemoryUtil; -import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.core.structs.ColoredLitWriterUnsafe; +import com.jozufozu.flywheel.core.structs.ColoredLitWriter; -public class OrientedWriterUnsafe extends ColoredLitWriterUnsafe { - public OrientedWriterUnsafe(StructType structType, ByteBuffer byteBuffer) { - super(structType, byteBuffer); - } +public class OrientedWriter extends ColoredLitWriter { + public static final OrientedWriter INSTANCE = new OrientedWriter(); @Override - protected void writeInternal(OrientedPart d) { - long ptr = writePointer; - super.writeInternal(d); + public void write(long ptr, OrientedPart d) { + super.write(ptr, d); MemoryUtil.memPutFloat(ptr + 6, d.posX); MemoryUtil.memPutFloat(ptr + 10, d.posY); diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedPart.java b/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedPart.java similarity index 97% rename from src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedPart.java rename to src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedPart.java index 865f5bccd..215bfd913 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedPart.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedPart.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.structs.model; +package com.jozufozu.flywheel.core.structs.transformed; import com.jozufozu.flywheel.core.structs.ColoredLitPart; import com.jozufozu.flywheel.core.structs.StructTypes; diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedStorageWriter.java b/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedStorageWriter.java similarity index 94% rename from src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedStorageWriter.java rename to src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedStorageWriter.java index 70619bdd1..1f05a3e1d 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedStorageWriter.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedStorageWriter.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.core.structs.model; +package com.jozufozu.flywheel.core.structs.transformed; import org.lwjgl.system.MemoryUtil; diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedType.java b/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedType.java similarity index 88% rename from src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedType.java rename to src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedType.java index 86b727125..aa6ba75d9 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedType.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedType.java @@ -1,6 +1,4 @@ -package com.jozufozu.flywheel.core.structs.model; - -import java.nio.ByteBuffer; +package com.jozufozu.flywheel.core.structs.transformed; import com.jozufozu.flywheel.api.struct.StorageBufferWriter; import com.jozufozu.flywheel.api.struct.StructType; @@ -30,8 +28,8 @@ public class TransformedType implements StructType { } @Override - public StructWriter getWriter(ByteBuffer backing) { - return new TransformedWriterUnsafe(this, backing); + public StructWriter getWriter() { + return TransformedWriter.INSTANCE; } @Override @@ -50,7 +48,7 @@ public class TransformedType implements StructType { } @Override - public VertexTransformer getVertexTransformer() { + public VertexTransformer getVertexTransformer() { return (vertexList, struct, level) -> { Vector4f pos = new Vector4f(); Vector3f normal = new Vector3f(); diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedWriter.java b/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedWriter.java new file mode 100644 index 000000000..c6d4383ca --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedWriter.java @@ -0,0 +1,17 @@ +package com.jozufozu.flywheel.core.structs.transformed; + +import com.jozufozu.flywheel.core.structs.ColoredLitWriter; +import com.jozufozu.flywheel.util.extension.MatrixExtension; + +public class TransformedWriter extends ColoredLitWriter { + public static final TransformedWriter INSTANCE = new TransformedWriter(); + + @Override + public void write(long ptr, TransformedPart d) { + super.write(ptr, d); + ptr += 6; + + ((MatrixExtension) (Object) d.model).flywheel$writeUnsafe(ptr); + ((MatrixExtension) (Object) d.normal).flywheel$writeUnsafe(ptr + 4 * 16); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedWriterUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedWriterUnsafe.java new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/java/com/jozufozu/flywheel/backend/struct/package-info.java b/src/main/java/com/jozufozu/flywheel/core/structs/transformed/package-info.java similarity index 75% rename from src/main/java/com/jozufozu/flywheel/backend/struct/package-info.java rename to src/main/java/com/jozufozu/flywheel/core/structs/transformed/package-info.java index d4cbaadf2..2ca2a5ed4 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/struct/package-info.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/transformed/package-info.java @@ -1,5 +1,5 @@ @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault -package com.jozufozu.flywheel.backend.struct; +package com.jozufozu.flywheel.core.structs.transformed; import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java index 76579490e..05cfdc8b3 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java @@ -9,22 +9,18 @@ import com.mojang.blaze3d.systems.RenderSystem; public class FogProvider extends UniformProvider { - - @Override public int getActualByteSize() { return 16 + 8 + 4; } public void update() { - if (buffer == null) { + if (ptr == MemoryUtil.NULL) { return; } var color = RenderSystem.getShaderFogColor(); - long ptr = MemoryUtil.memAddress(buffer); - MemoryUtil.memPutFloat(ptr, color[0]); MemoryUtil.memPutFloat(ptr + 4, color[1]); MemoryUtil.memPutFloat(ptr + 8, color[2]); diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java index 9070a7eae..4082a3a0c 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/FrustumProvider.java @@ -37,7 +37,7 @@ public class FrustumProvider extends UniformProvider { } public void update(RenderContext context) { - if (buffer == null) { + if (ptr == MemoryUtil.NULL) { return; } @@ -51,8 +51,6 @@ public class FrustumProvider extends UniformProvider { var shiftedCuller = RenderContext.createCuller(context.viewProjection(), -camX, -camY, -camZ); - long ptr = MemoryUtil.memAddress(buffer); - shiftedCuller.getJozuPackedPlanes(ptr); notifier.signalChanged(); diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java b/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java index e20db4a78..e3ecee4ab 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java @@ -1,20 +1,18 @@ package com.jozufozu.flywheel.core.uniform; -import java.nio.ByteBuffer; import java.util.BitSet; import java.util.Collection; import java.util.List; import org.lwjgl.opengl.GL32; -import org.lwjgl.system.MemoryUtil; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.api.uniform.UniformProvider; +import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; -import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer; +import com.jozufozu.flywheel.backend.memory.MemoryBlock; import com.jozufozu.flywheel.core.ComponentRegistry; import com.jozufozu.flywheel.util.RenderMath; -import com.mojang.blaze3d.platform.MemoryTracker; public class UniformBuffer { @@ -33,13 +31,13 @@ public class UniformBuffer { return instance; } - private final MappedGlBuffer buffer; - private final ByteBuffer data; + private final GlBuffer buffer; + private final MemoryBlock data; private final BitSet changedBytes; private UniformBuffer() { - buffer = new MappedGlBuffer(GlBufferType.UNIFORM_BUFFER); + buffer = new GlBuffer(GlBufferType.UNIFORM_BUFFER); Collection providers = ComponentRegistry.getAllUniformProviders(); @@ -57,7 +55,7 @@ public class UniformBuffer { allocatedProviders = builder.build(); - data = MemoryTracker.create(totalBytes); + data = MemoryBlock.mallocTracked(totalBytes); changedBytes = new BitSet(totalBytes); for (Allocated p : allocatedProviders) { @@ -112,8 +110,8 @@ public class UniformBuffer { changedBytes.set(offset, offset + size); } - private void updatePtr(ByteBuffer bufferBase) { - provider.updatePtr(MemoryUtil.memSlice(bufferBase, offset, size), this); + private void updatePtr(MemoryBlock bufferBase) { + provider.updatePtr(bufferBase.ptr() + offset, this); } public UniformProvider provider() { diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java index 65ffb4077..3c8448744 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java @@ -31,7 +31,7 @@ public class ViewProvider extends UniformProvider { } public void update(RenderContext context) { - if (buffer == null) { + if (ptr == MemoryUtil.NULL) { return; } @@ -52,8 +52,6 @@ public class ViewProvider extends UniformProvider { var vp = context.viewProjection().copy(); vp.multiplyWithTranslation(-camX, -camY, -camZ); - long ptr = MemoryUtil.memAddress(buffer); - MatrixExtension.writeUnsafe(vp, ptr); MemoryUtil.memPutFloat(ptr + 64, camX); MemoryUtil.memPutFloat(ptr + 68, camY); diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/AbstractVertexList.java b/src/main/java/com/jozufozu/flywheel/core/vertex/AbstractVertexList.java index a68e0c943..d1524cac2 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/AbstractVertexList.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/AbstractVertexList.java @@ -1,49 +1,28 @@ package com.jozufozu.flywheel.core.vertex; -import java.nio.Buffer; -import java.nio.ByteBuffer; +import com.jozufozu.flywheel.api.vertex.ReusableVertexList; -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.api.vertex.VertexList; -import com.mojang.blaze3d.platform.MemoryTracker; -import com.mojang.blaze3d.vertex.BufferBuilder; - -public abstract class AbstractVertexList implements VertexList, AutoCloseable { - - protected final ByteBuffer contents; - protected final long base; - protected final int vertexCount; - - protected AbstractVertexList(ByteBuffer copyFrom, int vertexCount) { - this.contents = MemoryTracker.create(copyFrom.capacity()); - this.vertexCount = vertexCount; - this.base = MemoryUtil.memAddress(this.contents); - init(copyFrom); - } - - public AbstractVertexList(BufferBuilder builder) { - var pair = builder.popNextBuffer(); - ByteBuffer copyFrom = pair.getSecond(); - this.contents = MemoryTracker.create(copyFrom.capacity()); - this.vertexCount = pair.getFirst().vertexCount(); - this.base = MemoryUtil.memAddress(this.contents); - init(copyFrom); - } - - private void init(ByteBuffer copyFrom) { - this.contents.order(copyFrom.order()); - this.contents.put(copyFrom); - ((Buffer) this.contents).flip(); - } - - @Override - public void close() { - MemoryUtil.memFree(contents); - } +public abstract class AbstractVertexList implements ReusableVertexList { + protected long ptr; + protected int vertexCount; @Override public int getVertexCount() { return vertexCount; } + + @Override + public void setVertexCount(int vertexCount) { + this.vertexCount = vertexCount; + } + + @Override + public long ptr() { + return ptr; + } + + @Override + public void ptr(long ptr) { + this.ptr = ptr; + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java index 9f37d06b8..e916d5ce3 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java @@ -1,7 +1,5 @@ package com.jozufozu.flywheel.core.vertex; -import java.nio.ByteBuffer; - import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.layout.BufferLayout; @@ -9,7 +7,6 @@ import com.jozufozu.flywheel.core.layout.CommonItems; import com.jozufozu.flywheel.core.source.FileResolution; public class BlockVertex implements VertexType { - public static final BufferLayout FORMAT = BufferLayout.builder() .addItems(CommonItems.VEC3, CommonItems.RGBA, @@ -24,18 +21,13 @@ public class BlockVertex implements VertexType { return FORMAT; } - @Override - public BlockWriterUnsafe createWriter(ByteBuffer buffer) { - return new BlockWriterUnsafe(this, buffer); - } - - @Override - public BlockVertexListUnsafe createReader(ByteBuffer buffer, int vertexCount) { - return new BlockVertexListUnsafe(buffer, vertexCount); - } - @Override public FileResolution getLayoutShader() { return Components.Files.BLOCK_LAYOUT; } + + @Override + public BlockVertexList createVertexList() { + return new BlockVertexList(); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexList.java b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexList.java index a0423246a..ecfa8f277 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexList.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexList.java @@ -1,72 +1,61 @@ package com.jozufozu.flywheel.core.vertex; +import org.lwjgl.system.MemoryUtil; + import com.jozufozu.flywheel.util.RenderMath; -import com.mojang.blaze3d.vertex.BufferBuilder; import net.minecraft.client.renderer.texture.OverlayTexture; public class BlockVertexList extends AbstractVertexList { + protected static final int STRIDE = 32; - private final int stride; - - public BlockVertexList(BufferBuilder builder) { - super(builder); - this.stride = builder.getVertexFormat() - .getVertexSize(); - } - - @Override - public boolean isEmpty() { - return vertexCount == 0; - } - - private int vertIdx(int vertexIndex) { - return vertexIndex * stride; + protected long idxPtr(int index) { + return ptr + index * STRIDE; } @Override public float x(int index) { - return contents.getFloat(vertIdx(index)); + return MemoryUtil.memGetFloat(idxPtr(index)); } @Override public float y(int index) { - return contents.getFloat(vertIdx(index) + 4); + return MemoryUtil.memGetFloat(idxPtr(index) + 4); } @Override public float z(int index) { - return contents.getFloat(vertIdx(index) + 8); + return MemoryUtil.memGetFloat(idxPtr(index) + 8); } @Override public byte r(int index) { - return contents.get(vertIdx(index) + 12); + return MemoryUtil.memGetByte(idxPtr(index) + 12); } @Override public byte g(int index) { - return contents.get(vertIdx(index) + 13); + return MemoryUtil.memGetByte(idxPtr(index) + 13); } @Override public byte b(int index) { - return contents.get(vertIdx(index) + 14); + return MemoryUtil.memGetByte(idxPtr(index) + 14); } @Override public byte a(int index) { - return contents.get(vertIdx(index) + 15); + return MemoryUtil.memGetByte(idxPtr(index) + 15); } @Override public float u(int index) { - return contents.getFloat(vertIdx(index) + 16); + return MemoryUtil.memGetFloat(idxPtr(index) + 16); } @Override public float v(int index) { - return contents.getFloat(vertIdx(index) + 20); + return MemoryUtil.memGetFloat(idxPtr(index) + 20); } @Override @@ -76,22 +65,95 @@ public class BlockVertexList extends AbstractVertexList { @Override public int light(int index) { - return contents.getInt(vertIdx(index) + 24); + return MemoryUtil.memGetInt(idxPtr(index) + 24) << 4; } @Override public float normalX(int index) { - return RenderMath.f(contents.get(vertIdx(index) + 28)); + return RenderMath.f(MemoryUtil.memGetByte(idxPtr(index) + 28)); } @Override public float normalY(int index) { - return RenderMath.f(contents.get(vertIdx(index) + 29)); + return RenderMath.f(MemoryUtil.memGetByte(idxPtr(index) + 29)); } @Override public float normalZ(int index) { - return RenderMath.f(contents.get(vertIdx(index) + 30)); + return RenderMath.f(MemoryUtil.memGetByte(idxPtr(index) + 30)); } + @Override + public void x(int index, float x) { + MemoryUtil.memPutFloat(idxPtr(index), x); + } + + @Override + public void y(int index, float y) { + MemoryUtil.memPutFloat(idxPtr(index) + 4, y); + } + + @Override + public void z(int index, float z) { + MemoryUtil.memPutFloat(idxPtr(index) + 8, z); + } + + @Override + public void r(int index, byte r) { + MemoryUtil.memPutByte(idxPtr(index) + 12, r); + } + + @Override + public void g(int index, byte g) { + MemoryUtil.memPutByte(idxPtr(index) + 13, g); + } + + @Override + public void b(int index, byte b) { + MemoryUtil.memPutByte(idxPtr(index) + 14, b); + } + + @Override + public void a(int index, byte a) { + MemoryUtil.memPutByte(idxPtr(index) + 15, a); + } + + @Override + public void u(int index, float u) { + MemoryUtil.memPutFloat(idxPtr(index) + 16, u); + } + + @Override + public void v(int index, float v) { + MemoryUtil.memPutFloat(idxPtr(index) + 20, v); + } + + @Override + public void overlay(int index, int overlay) { + } + + @Override + public void light(int index, int light) { + MemoryUtil.memPutInt(idxPtr(index) + 24, light >> 4); + } + + @Override + public void normalX(int index, float normalX) { + MemoryUtil.memPutByte(idxPtr(index) + 28, RenderMath.nb(normalX)); + } + + @Override + public void normalY(int index, float normalY) { + MemoryUtil.memPutByte(idxPtr(index) + 29, RenderMath.nb(normalY)); + } + + @Override + public void normalZ(int index, float normalZ) { + MemoryUtil.memPutByte(idxPtr(index) + 30, RenderMath.nb(normalZ)); + } + + @Override + public void shiftPtr(int vertices) { + ptr += vertices * STRIDE; + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexListUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexListUnsafe.java deleted file mode 100644 index 2b272f76e..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexListUnsafe.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.jozufozu.flywheel.core.vertex; - -import java.nio.ByteBuffer; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.util.RenderMath; - -import net.minecraft.client.renderer.texture.OverlayTexture; - -public class BlockVertexListUnsafe extends AbstractVertexList { - - public BlockVertexListUnsafe(ByteBuffer copyFrom, int vertexCount) { - super(copyFrom, vertexCount); - } - - private long ptr(long index) { - return base + index * 32; - } - - @Override - public float x(int index) { - return MemoryUtil.memGetFloat(ptr(index)); - } - - @Override - public float y(int index) { - return MemoryUtil.memGetFloat(ptr(index) + 4); - } - - @Override - public float z(int index) { - return MemoryUtil.memGetFloat(ptr(index) + 8); - } - - @Override - public byte r(int index) { - return MemoryUtil.memGetByte(ptr(index) + 12); - } - - @Override - public byte g(int index) { - return MemoryUtil.memGetByte(ptr(index) + 13); - } - - @Override - public byte b(int index) { - return MemoryUtil.memGetByte(ptr(index) + 14); - } - - @Override - public byte a(int index) { - return MemoryUtil.memGetByte(ptr(index) + 15); - } - - @Override - public float u(int index) { - return MemoryUtil.memGetFloat(ptr(index) + 16); - } - - @Override - public float v(int index) { - return MemoryUtil.memGetFloat(ptr(index) + 20); - } - - @Override - public int overlay(int index) { - return OverlayTexture.NO_OVERLAY; - } - - @Override - public int light(int index) { - return MemoryUtil.memGetInt(ptr(index) + 24); - } - - @Override - public float normalX(int index) { - return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 28)); - } - - @Override - public float normalY(int index) { - return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 29)); - } - - @Override - public float normalZ(int index) { - return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 30)); - } - -} diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockWriterUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockWriterUnsafe.java deleted file mode 100644 index 556e352d9..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockWriterUnsafe.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.jozufozu.flywheel.core.vertex; - -import java.nio.ByteBuffer; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.api.vertex.VertexList; -import com.jozufozu.flywheel.util.RenderMath; - -public class BlockWriterUnsafe extends VertexWriterUnsafe { - - public BlockWriterUnsafe(BlockVertex type, ByteBuffer buffer) { - super(type, buffer); - } - - @Override - public void writeVertex(VertexList list, int i) { - float x = list.x(i); - float y = list.y(i); - float z = list.z(i); - - float xN = list.normalX(i); - float yN = list.normalY(i); - float zN = list.normalZ(i); - - float u = list.u(i); - float v = list.v(i); - - byte r = list.r(i); - byte g = list.g(i); - byte b = list.b(i); - byte a = list.a(i); - - int light = list.light(i); - - putVertex(x, y, z, u, v, r, g, b, a, light, xN, yN, zN); - } - - public void putVertex(float x, float y, float z, float u, float v, byte r, byte g, byte b, byte a, int light, float nX, float nY, float nZ) { - MemoryUtil.memPutFloat(ptr, x); - MemoryUtil.memPutFloat(ptr + 4, y); - MemoryUtil.memPutFloat(ptr + 8, z); - MemoryUtil.memPutByte(ptr + 12, r); - MemoryUtil.memPutByte(ptr + 13, g); - MemoryUtil.memPutByte(ptr + 14, b); - MemoryUtil.memPutByte(ptr + 15, a); - MemoryUtil.memPutFloat(ptr + 16, u); - MemoryUtil.memPutFloat(ptr + 20, v); - MemoryUtil.memPutInt(ptr + 24, (light >> 4) & 0xF000F); - MemoryUtil.memPutByte(ptr + 28, RenderMath.nb(nX)); - MemoryUtil.memPutByte(ptr + 29, RenderMath.nb(nY)); - MemoryUtil.memPutByte(ptr + 30, RenderMath.nb(nZ)); - - ptr += 32; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/VertexFormatInfo.java b/src/main/java/com/jozufozu/flywheel/core/vertex/InferredVertexFormatInfo.java similarity index 88% rename from src/main/java/com/jozufozu/flywheel/backend/instancing/batching/VertexFormatInfo.java rename to src/main/java/com/jozufozu/flywheel/core/vertex/InferredVertexFormatInfo.java index 35f273508..c47cb837e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/VertexFormatInfo.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/InferredVertexFormatInfo.java @@ -1,9 +1,9 @@ -package com.jozufozu.flywheel.backend.instancing.batching; +package com.jozufozu.flywheel.core.vertex; import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.blaze3d.vertex.VertexFormatElement; -public class VertexFormatInfo { +public class InferredVertexFormatInfo { public final VertexFormat format; public final int stride; @@ -14,7 +14,7 @@ public class VertexFormatInfo { public final int lightOffset; public final int normalOffset; - public VertexFormatInfo(VertexFormat format) { + public InferredVertexFormatInfo(VertexFormat format) { this.format = format; stride = format.getVertexSize(); @@ -51,7 +51,7 @@ public class VertexFormatInfo { this.normalOffset = normalOffset; } - protected VertexFormatInfo(VertexFormatInfo formatInfo) { + protected InferredVertexFormatInfo(InferredVertexFormatInfo formatInfo) { format = formatInfo.format; stride = formatInfo.stride; positionOffset = formatInfo.positionOffset; diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/InferredVertexListImpl.java b/src/main/java/com/jozufozu/flywheel/core/vertex/InferredVertexListImpl.java new file mode 100644 index 000000000..c074e37bf --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/InferredVertexListImpl.java @@ -0,0 +1,214 @@ +package com.jozufozu.flywheel.core.vertex; + +import org.lwjgl.system.MemoryUtil; + +import com.jozufozu.flywheel.api.vertex.ReusableVertexList; +import com.jozufozu.flywheel.util.RenderMath; + +import net.minecraft.client.renderer.texture.OverlayTexture; + +public final class InferredVertexListImpl extends InferredVertexFormatInfo implements ReusableVertexList { + private long ptr; + private int vertexCount; + + public InferredVertexListImpl(InferredVertexFormatInfo formatInfo) { + super(formatInfo); + } + + private long idxPtr(int index) { + return ptr + index * stride; + } + + @Override + public float x(int index) { + if (positionOffset < 0) return 0; + return MemoryUtil.memGetFloat(idxPtr(index) + positionOffset); + } + + @Override + public float y(int index) { + if (positionOffset < 0) return 0; + return MemoryUtil.memGetFloat(idxPtr(index) + positionOffset + 4); + } + + @Override + public float z(int index) { + if (positionOffset < 0) return 0; + return MemoryUtil.memGetFloat(idxPtr(index) + positionOffset + 8); + } + + @Override + public byte r(int index) { + if (colorOffset < 0) return 0; + return MemoryUtil.memGetByte(idxPtr(index) + colorOffset); + } + + @Override + public byte g(int index) { + if (colorOffset < 0) return 0; + return MemoryUtil.memGetByte(idxPtr(index) + colorOffset + 1); + } + + @Override + public byte b(int index) { + if (colorOffset < 0) return 0; + return MemoryUtil.memGetByte(idxPtr(index) + colorOffset + 2); + } + + @Override + public byte a(int index) { + if (colorOffset < 0) return 0; + return MemoryUtil.memGetByte(idxPtr(index) + colorOffset + 3); + } + + @Override + public float u(int index) { + if (textureOffset < 0) return 0; + return MemoryUtil.memGetFloat(idxPtr(index) + textureOffset); + } + + @Override + public float v(int index) { + if (textureOffset < 0) return 0; + return MemoryUtil.memGetFloat(idxPtr(index) + textureOffset + 4); + } + + @Override + public int overlay(int index) { + if (overlayOffset < 0) return OverlayTexture.NO_OVERLAY; + return MemoryUtil.memGetInt(idxPtr(index) + overlayOffset); + } + + @Override + public int light(int index) { + if (lightOffset < 0) return 0; + return MemoryUtil.memGetInt(idxPtr(index) + lightOffset); + } + + @Override + public float normalX(int index) { + if (normalOffset < 0) return 0; + return RenderMath.f(MemoryUtil.memGetByte(idxPtr(index) + normalOffset)); + } + + @Override + public float normalY(int index) { + if (normalOffset < 0) return 0; + return RenderMath.f(MemoryUtil.memGetByte(idxPtr(index) + normalOffset + 1)); + } + + @Override + public float normalZ(int index) { + if (normalOffset < 0) return 0; + return RenderMath.f(MemoryUtil.memGetByte(idxPtr(index) + normalOffset + 2)); + } + + @Override + public void x(int index, float x) { + if (positionOffset < 0) return; + MemoryUtil.memPutFloat(idxPtr(index) + positionOffset, x); + } + + @Override + public void y(int index, float y) { + if (positionOffset < 0) return; + MemoryUtil.memPutFloat(idxPtr(index) + positionOffset + 4, y); + } + + @Override + public void z(int index, float z) { + if (positionOffset < 0) return; + MemoryUtil.memPutFloat(idxPtr(index) + positionOffset + 8, z); + } + + @Override + public void r(int index, byte r) { + if (colorOffset < 0) return; + MemoryUtil.memPutByte(idxPtr(index) + colorOffset, r); + } + + @Override + public void g(int index, byte g) { + if (colorOffset < 0) return; + MemoryUtil.memPutByte(idxPtr(index) + colorOffset + 1, g); + } + + @Override + public void b(int index, byte b) { + if (colorOffset < 0) return; + MemoryUtil.memPutByte(idxPtr(index) + colorOffset + 2, b); + } + + @Override + public void a(int index, byte a) { + if (colorOffset < 0) return; + MemoryUtil.memPutByte(idxPtr(index) + colorOffset + 3, a); + } + + @Override + public void u(int index, float u) { + if (textureOffset < 0) return; + MemoryUtil.memPutFloat(idxPtr(index) + textureOffset, u); + } + + @Override + public void v(int index, float v) { + if (textureOffset < 0) return; + MemoryUtil.memPutFloat(idxPtr(index) + textureOffset + 4, v); + } + + @Override + public void overlay(int index, int overlay) { + if (overlayOffset < 0) return; + MemoryUtil.memPutInt(idxPtr(index) + overlayOffset, overlay); + } + + @Override + public void light(int index, int light) { + if (lightOffset < 0) return; + MemoryUtil.memPutInt(idxPtr(index) + lightOffset, light); + } + + @Override + public void normalX(int index, float normalX) { + if (normalOffset < 0) return; + MemoryUtil.memPutByte(idxPtr(index) + normalOffset, RenderMath.nb(normalX)); + } + + @Override + public void normalY(int index, float normalY) { + if (normalOffset < 0) return; + MemoryUtil.memPutByte(idxPtr(index) + normalOffset + 1, RenderMath.nb(normalY)); + } + + @Override + public void normalZ(int index, float normalZ) { + if (normalOffset < 0) return; + MemoryUtil.memPutByte(idxPtr(index) + normalOffset + 2, RenderMath.nb(normalZ)); + } + + @Override + public int getVertexCount() { + return vertexCount; + } + + @Override + public long ptr() { + return ptr; + } + + @Override + public void ptr(long ptr) { + this.ptr = ptr; + } + + @Override + public void shiftPtr(int vertices) { + ptr += vertices * stride; + } + + @Override + public void setVertexCount(int vertexCount) { + this.vertexCount = vertexCount; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/InferredVertexListProviderImpl.java b/src/main/java/com/jozufozu/flywheel/core/vertex/InferredVertexListProviderImpl.java new file mode 100644 index 000000000..fd976aa6b --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/InferredVertexListProviderImpl.java @@ -0,0 +1,20 @@ +package com.jozufozu.flywheel.core.vertex; + +import com.jozufozu.flywheel.api.vertex.ReusableVertexList; +import com.jozufozu.flywheel.api.vertex.VertexListProvider; +import com.mojang.blaze3d.vertex.VertexFormat; + +public class InferredVertexListProviderImpl implements VertexListProvider { + private final VertexFormat format; + private final InferredVertexFormatInfo formatInfo; + + public InferredVertexListProviderImpl(VertexFormat format) { + this.format = format; + formatInfo = new InferredVertexFormatInfo(format); + } + + @Override + public ReusableVertexList createVertexList() { + return new InferredVertexListImpl(formatInfo); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java index 2c115041c..131bfc6e6 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java @@ -1,7 +1,5 @@ package com.jozufozu.flywheel.core.vertex; -import java.nio.ByteBuffer; - import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.layout.BufferLayout; @@ -9,7 +7,6 @@ import com.jozufozu.flywheel.core.layout.CommonItems; import com.jozufozu.flywheel.core.source.FileResolution; public class PosTexNormalVertex implements VertexType { - public static final BufferLayout FORMAT = BufferLayout.builder() .addItems(CommonItems.VEC3, CommonItems.UV, CommonItems.NORMAL) .build(); @@ -19,18 +16,13 @@ public class PosTexNormalVertex implements VertexType { return FORMAT; } - @Override - public PosTexNormalWriterUnsafe createWriter(ByteBuffer buffer) { - return new PosTexNormalWriterUnsafe(this, buffer); - } - - @Override - public PosTexNormalVertexListUnsafe createReader(ByteBuffer buffer, int vertexCount) { - return new PosTexNormalVertexListUnsafe(buffer, vertexCount); - } - @Override public FileResolution getLayoutShader() { return Components.Files.POS_TEX_NORMAL_LAYOUT; } + + @Override + public PosTexNormalVertexList createVertexList() { + return new PosTexNormalVertexList(); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertexList.java b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertexList.java new file mode 100644 index 000000000..4ac841c04 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertexList.java @@ -0,0 +1,154 @@ +package com.jozufozu.flywheel.core.vertex; + +import org.lwjgl.system.MemoryUtil; + +import com.jozufozu.flywheel.util.RenderMath; + +import net.minecraft.client.renderer.texture.OverlayTexture; + +public class PosTexNormalVertexList extends AbstractVertexList { + protected static final int STRIDE = 23; + + protected long idxPtr(long idx) { + return ptr + idx * STRIDE; + } + + @Override + public float x(int index) { + return MemoryUtil.memGetFloat(idxPtr(index)); + } + + @Override + public float y(int index) { + return MemoryUtil.memGetFloat(idxPtr(index) + 4); + } + + @Override + public float z(int index) { + return MemoryUtil.memGetFloat(idxPtr(index) + 8); + } + + @Override + public byte r(int index) { + return (byte) 0xFF; + } + + @Override + public byte g(int index) { + return (byte) 0xFF; + } + + @Override + public byte b(int index) { + return (byte) 0xFF; + } + + @Override + public byte a(int index) { + return (byte) 0xFF; + } + + @Override + public float u(int index) { + return MemoryUtil.memGetFloat(idxPtr(index) + 12); + } + + @Override + public float v(int index) { + return MemoryUtil.memGetFloat(idxPtr(index) + 16); + } + + @Override + public int overlay(int index) { + return OverlayTexture.NO_OVERLAY; + } + + @Override + public int light(int index) { + return 0; + } + + @Override + public float normalX(int index) { + return RenderMath.f(MemoryUtil.memGetByte(idxPtr(index) + 20)); + } + + @Override + public float normalY(int index) { + return RenderMath.f(MemoryUtil.memGetByte(idxPtr(index) + 21)); + } + + @Override + public float normalZ(int index) { + return RenderMath.f(MemoryUtil.memGetByte(idxPtr(index) + 22)); + } + + @Override + public void x(int index, float x) { + MemoryUtil.memPutFloat(idxPtr(index), x); + } + + @Override + public void y(int index, float y) { + MemoryUtil.memPutFloat(idxPtr(index) + 4, y); + } + + @Override + public void z(int index, float z) { + MemoryUtil.memPutFloat(idxPtr(index) + 8, z); + } + + @Override + public void r(int index, byte r) { + } + + @Override + public void g(int index, byte g) { + } + + @Override + public void b(int index, byte b) { + } + + @Override + public void a(int index, byte a) { + } + + @Override + public void u(int index, float u) { + MemoryUtil.memPutFloat(idxPtr(index) + 12, u); + } + + @Override + public void v(int index, float v) { + MemoryUtil.memPutFloat(idxPtr(index) + 16, v); + } + + @Override + public void overlay(int index, int overlay) { + } + + @Override + public void light(int index, int light) { + } + + @Override + public void normalX(int index, float normalX) { + MemoryUtil.memPutByte(idxPtr(index) + 20, RenderMath.nb(normalX)); + } + + @Override + public void normalY(int index, float normalY) { + MemoryUtil.memPutByte(idxPtr(index) + 21, RenderMath.nb(normalY)); + } + + @Override + public void normalZ(int index, float normalZ) { + MemoryUtil.memPutByte(idxPtr(index) + 22, RenderMath.nb(normalZ)); + } + + @Override + public void shiftPtr(int vertices) { + ptr += vertices * STRIDE; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertexListUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertexListUnsafe.java deleted file mode 100644 index df1091a97..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertexListUnsafe.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.jozufozu.flywheel.core.vertex; - -import java.nio.ByteBuffer; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.util.RenderMath; - -import net.minecraft.client.renderer.texture.OverlayTexture; - -public class PosTexNormalVertexListUnsafe extends AbstractVertexList { - - public PosTexNormalVertexListUnsafe(ByteBuffer copyFrom, int vertexCount) { - super(copyFrom, vertexCount); - } - - private long ptr(long idx) { - return base + idx * 23; - } - - @Override - public float x(int index) { - return MemoryUtil.memGetFloat(ptr(index)); - } - - @Override - public float y(int index) { - return MemoryUtil.memGetFloat(ptr(index) + 4); - } - - @Override - public float z(int index) { - return MemoryUtil.memGetFloat(ptr(index) + 8); - } - - @Override - public byte r(int index) { - return (byte) 0xFF; - } - - @Override - public byte g(int index) { - return (byte) 0xFF; - } - - @Override - public byte b(int index) { - return (byte) 0xFF; - } - - @Override - public byte a(int index) { - return (byte) 0xFF; - } - - @Override - public float u(int index) { - return MemoryUtil.memGetFloat(ptr(index) + 12); - } - - @Override - public float v(int index) { - return MemoryUtil.memGetFloat(ptr(index) + 16); - } - - @Override - public int overlay(int index) { - return OverlayTexture.NO_OVERLAY; - } - - @Override - public int light(int index) { - return 0; - } - - @Override - public float normalX(int index) { - return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 20)); - } - - @Override - public float normalY(int index) { - return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 21)); - } - - @Override - public float normalZ(int index) { - return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 22)); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalWriterUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalWriterUnsafe.java deleted file mode 100644 index 7e97962bc..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalWriterUnsafe.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.jozufozu.flywheel.core.vertex; - -import java.nio.ByteBuffer; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.api.vertex.VertexList; -import com.jozufozu.flywheel.util.RenderMath; - -public class PosTexNormalWriterUnsafe extends VertexWriterUnsafe { - - public PosTexNormalWriterUnsafe(PosTexNormalVertex type, ByteBuffer buffer) { - super(type, buffer); - } - - @Override - public void writeVertex(VertexList list, int i) { - float x = list.x(i); - float y = list.y(i); - float z = list.z(i); - - float u = list.u(i); - float v = list.v(i); - - float xN = list.normalX(i); - float yN = list.normalY(i); - float zN = list.normalZ(i); - - putVertex(x, y, z, xN, yN, zN, u, v); - } - - public void putVertex(float x, float y, float z, float nX, float nY, float nZ, float u, float v) { - MemoryUtil.memPutFloat(ptr, x); - MemoryUtil.memPutFloat(ptr + 4, y); - MemoryUtil.memPutFloat(ptr + 8, z); - MemoryUtil.memPutFloat(ptr + 12, u); - MemoryUtil.memPutFloat(ptr + 16, v); - MemoryUtil.memPutByte(ptr + 20, RenderMath.nb(nX)); - MemoryUtil.memPutByte(ptr + 21, RenderMath.nb(nY)); - MemoryUtil.memPutByte(ptr + 22, RenderMath.nb(nZ)); - - ptr += 23; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/TrackedVertexList.java b/src/main/java/com/jozufozu/flywheel/core/vertex/TrackedVertexList.java deleted file mode 100644 index 00cb24eec..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/TrackedVertexList.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.jozufozu.flywheel.core.vertex; - -import java.lang.ref.Cleaner; -import java.nio.Buffer; -import java.nio.ByteBuffer; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.api.vertex.VertexList; -import com.jozufozu.flywheel.backend.FlywheelMemory; -import com.mojang.blaze3d.platform.MemoryTracker; - -public abstract class TrackedVertexList implements VertexList, AutoCloseable { - - protected final ByteBuffer contents; - protected final long base; - protected final int vertexCount; - private final Cleaner.Cleanable cleanable; - - protected TrackedVertexList(ByteBuffer copyFrom, int vertexCount) { - this.contents = MemoryTracker.create(copyFrom.capacity()); - this.contents.order(copyFrom.order()); - this.contents.put(copyFrom); - ((Buffer) this.contents).flip(); - - this.cleanable = FlywheelMemory.track(this, this.contents); - - this.base = MemoryUtil.memAddress(this.contents); - this.vertexCount = vertexCount; - } - - @Override - public void close() { - cleanable.clean(); - } - - @Override - public int getVertexCount() { - return vertexCount; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/VertexListProviderRegistry.java b/src/main/java/com/jozufozu/flywheel/core/vertex/VertexListProviderRegistry.java new file mode 100644 index 000000000..3a597d8db --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/VertexListProviderRegistry.java @@ -0,0 +1,55 @@ +package com.jozufozu.flywheel.core.vertex; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.jetbrains.annotations.Nullable; + +import com.jozufozu.flywheel.api.vertex.VertexListProvider; +import com.mojang.blaze3d.vertex.VertexFormat; + +public class VertexListProviderRegistry { + private static final Map HOLDERS = new ConcurrentHashMap<>(); + + private static Holder getOrCreateHolder(VertexFormat format) { + return HOLDERS.computeIfAbsent(format, Holder::new); + } + + public static void register(VertexFormat format, VertexListProvider provider) { + getOrCreateHolder(format).registeredProvider = provider; + } + + @Nullable + public static VertexListProvider get(VertexFormat format) { + return getOrCreateHolder(format).get(); + } + + public static VertexListProvider getOrInfer(VertexFormat format) { + return getOrCreateHolder(format).getOrInfer(); + } + + private static class Holder { + public final VertexFormat format; + public VertexListProvider registeredProvider; + public VertexListProvider inferredProvider; + + public Holder(VertexFormat format) { + this.format = format; + } + + @Nullable + public VertexListProvider get() { + return registeredProvider; + } + + public VertexListProvider getOrInfer() { + if (registeredProvider != null) { + return registeredProvider; + } + if (inferredProvider == null) { + inferredProvider = new InferredVertexListProviderImpl(format); + } + return inferredProvider; + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/VertexWriterUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/vertex/VertexWriterUnsafe.java deleted file mode 100644 index f4f31c7d0..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/VertexWriterUnsafe.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.jozufozu.flywheel.core.vertex; - -import java.nio.ByteBuffer; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.api.vertex.VertexList; -import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.api.vertex.VertexWriter; - -public abstract class VertexWriterUnsafe implements VertexWriter { - - public final V type; - protected final ByteBuffer buffer; - protected long ptr; - - protected VertexWriterUnsafe(V type, ByteBuffer buffer) { - this.type = type; - this.buffer = buffer; - this.ptr = MemoryUtil.memAddress(buffer); - } - - @Override - public void seek(long offset) { - buffer.position((int) offset); - ptr = MemoryUtil.memAddress(buffer); - } - - @Override - public VertexList intoReader(int vertices) { - return type.createReader(buffer, vertices); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java b/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java index 1310235f7..793f519ca 100644 --- a/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java +++ b/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java @@ -4,9 +4,10 @@ import java.util.ArrayList; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.FlywheelMemory; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +import com.jozufozu.flywheel.backend.memory.FlwMemoryTracker; import com.jozufozu.flywheel.light.LightUpdater; +import com.jozufozu.flywheel.util.StringUtil; import com.jozufozu.flywheel.util.WorldAttached; import net.minecraft.client.Minecraft; @@ -24,10 +25,7 @@ public class ForgeEvents { InstancedRenderDispatcher.getDebugString(debug); - // TODO: compress into one line - debug.add("Memory used:"); - debug.add("GPU: " + FlywheelMemory.getGPUMemory()); - debug.add("CPU: " + FlywheelMemory.getCPUMemory()); + debug.add("Memory Usage: CPU: " + StringUtil.formatBytes(FlwMemoryTracker.getCPUMemory()) + ", GPU: " + StringUtil.formatBytes(FlwMemoryTracker.getGPUMemory())); } } diff --git a/src/main/java/com/jozufozu/flywheel/light/GPULightVolume.java b/src/main/java/com/jozufozu/flywheel/light/GPULightVolume.java index 673670973..233b84504 100644 --- a/src/main/java/com/jozufozu/flywheel/light/GPULightVolume.java +++ b/src/main/java/com/jozufozu/flywheel/light/GPULightVolume.java @@ -73,7 +73,7 @@ public class GPULightVolume extends LightVolume { public void bind() { // just in case something goes wrong, or we accidentally call this before this volume is properly disposed of. - if (lightData == null || lightData.capacity() == 0) return; + if (lightData == null || lightData.size() == 0) return; textureUnit.makeActive(); glTexture.bind(); @@ -93,7 +93,7 @@ public class GPULightVolume extends LightVolume { int sizeY = box.sizeY(); int sizeZ = box.sizeZ(); - glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, sizeX, sizeY, sizeZ, GL30.GL_RG, GL_UNSIGNED_BYTE, lightData); + glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, sizeX, sizeY, sizeZ, GL30.GL_RG, GL_UNSIGNED_BYTE, lightData.ptr()); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4 is the default bufferDirty = false; diff --git a/src/main/java/com/jozufozu/flywheel/light/LightVolume.java b/src/main/java/com/jozufozu/flywheel/light/LightVolume.java index 31245dea9..ef1dc4f88 100644 --- a/src/main/java/com/jozufozu/flywheel/light/LightVolume.java +++ b/src/main/java/com/jozufozu/flywheel/light/LightVolume.java @@ -1,9 +1,8 @@ package com.jozufozu.flywheel.light; -import java.nio.ByteBuffer; - import org.lwjgl.system.MemoryUtil; +import com.jozufozu.flywheel.backend.memory.MemoryBlock; import com.jozufozu.flywheel.util.box.GridAlignedBB; import com.jozufozu.flywheel.util.box.ImmutableBox; @@ -15,13 +14,53 @@ public class LightVolume implements ImmutableBox, LightListener { protected final BlockAndTintGetter level; protected final GridAlignedBB box = new GridAlignedBB(); - protected ByteBuffer lightData; + protected MemoryBlock lightData; public LightVolume(BlockAndTintGetter level, ImmutableBox sampleVolume) { this.level = level; this.setBox(sampleVolume); - this.lightData = MemoryUtil.memAlloc(this.box.volume() * 2); + this.lightData = MemoryBlock.malloc(this.box.volume() * 2); + } + + @Override + public ImmutableBox getVolume() { + return box; + } + + @Override + public int getMinX() { + return box.getMinX(); + } + + @Override + public int getMinY() { + return box.getMinY(); + } + + @Override + public int getMinZ() { + return box.getMinZ(); + } + + @Override + public int getMaxX() { + return box.getMaxX(); + } + + @Override + public int getMaxY() { + return box.getMaxY(); + } + + @Override + public int getMaxZ() { + return box.getMaxZ(); + } + + @Override + public boolean isListenerInvalid() { + return lightData == null; } protected void setBox(ImmutableBox box) { @@ -30,47 +69,143 @@ public class LightVolume implements ImmutableBox, LightListener { public short getPackedLight(int x, int y, int z) { if (box.contains(x, y, z)) { - return lightData.getShort(worldPosToBufferIndex(x, y, z)); + return MemoryUtil.memGetShort(worldPosToPtr(x, y, z)); } else { return 0; } } - public int getMinX() { - return box.getMinX(); - } - - public int getMinY() { - return box.getMinY(); - } - - public int getMinZ() { - return box.getMinZ(); - } - - public int getMaxX() { - return box.getMaxX(); - } - - public int getMaxY() { - return box.getMaxY(); - } - - public int getMaxZ() { - return box.getMaxZ(); - } - public void move(ImmutableBox newSampleVolume) { if (lightData == null) return; setBox(newSampleVolume); int neededCapacity = box.volume() * 2; - if (neededCapacity > lightData.capacity()) { - lightData = MemoryUtil.memRealloc(lightData, neededCapacity); + if (neededCapacity > lightData.size()) { + lightData = lightData.realloc(neededCapacity); } initialize(); } + /** + * Completely (re)populate this volume with block and sky lighting data. + * This is expensive and should be avoided. + */ + public void initialize() { + if (lightData == null) return; + + copyLight(getVolume()); + markDirty(); + } + + protected void markDirty() { + // noop + } + + public void delete() { + lightData.free(); + lightData = null; + } + + /** + * Copy all light from the world into this volume. + * + * @param worldVolume the region in the world to copy data from. + */ + public void copyLight(ImmutableBox worldVolume) { + BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); + + int xShift = box.getMinX(); + int yShift = box.getMinY(); + int zShift = box.getMinZ(); + + worldVolume.forEachContained((x, y, z) -> { + pos.set(x, y, z); + + int block = this.level.getBrightness(LightLayer.BLOCK, pos); + int sky = this.level.getBrightness(LightLayer.SKY, pos); + + writeLight(x - xShift, y - yShift, z - zShift, block, sky); + }); + } + + protected void writeLight(int x, int y, int z, int block, int sky) { + byte b = (byte) ((block & 0xF) << 4); + byte s = (byte) ((sky & 0xF) << 4); + + long ptr = boxPosToPtr(x, y, z); + MemoryUtil.memPutByte(ptr, b); + MemoryUtil.memPutByte(ptr + 1, s); + } + + /** + * Copy block light from the world into this volume. + * + * @param worldVolume the region in the world to copy data from. + */ + public void copyBlock(ImmutableBox worldVolume) { + var pos = new BlockPos.MutableBlockPos(); + + int xShift = box.getMinX(); + int yShift = box.getMinY(); + int zShift = box.getMinZ(); + + worldVolume.forEachContained((x, y, z) -> { + int light = this.level.getBrightness(LightLayer.BLOCK, pos.set(x, y, z)); + + writeBlock(x - xShift, y - yShift, z - zShift, light); + }); + } + + protected void writeBlock(int x, int y, int z, int block) { + byte b = (byte) ((block & 0xF) << 4); + + MemoryUtil.memPutByte(boxPosToPtr(x, y, z), b); + } + + /** + * Copy sky light from the world into this volume. + * + * @param worldVolume the region in the world to copy data from. + */ + public void copySky(ImmutableBox worldVolume) { + var pos = new BlockPos.MutableBlockPos(); + + int xShift = box.getMinX(); + int yShift = box.getMinY(); + int zShift = box.getMinZ(); + + worldVolume.forEachContained((x, y, z) -> { + int light = this.level.getBrightness(LightLayer.SKY, pos.set(x, y, z)); + + writeSky(x - xShift, y - yShift, z - zShift, light); + }); + } + + protected void writeSky(int x, int y, int z, int sky) { + byte s = (byte) ((sky & 0xF) << 4); + + MemoryUtil.memPutByte(boxPosToPtr(x, y, z) + 1, s); + } + + protected long worldPosToPtr(int x, int y, int z) { + return lightData.ptr() + worldPosToPtrOffset(x, y, z); + } + + protected long boxPosToPtr(int x, int y, int z) { + return lightData.ptr() + boxPosToPtrOffset(x, y, z); + } + + protected int worldPosToPtrOffset(int x, int y, int z) { + x -= box.getMinX(); + y -= box.getMinY(); + z -= box.getMinZ(); + return boxPosToPtrOffset(x, y, z); + } + + protected int boxPosToPtrOffset(int x, int y, int z) { + return (x + box.sizeX() * (y + z * box.sizeY())) * 2; + } + @Override public void onLightUpdate(LightLayer type, ImmutableBox changedVolume) { if (lightData == null) return; @@ -96,126 +231,4 @@ public class LightVolume implements ImmutableBox, LightListener { markDirty(); } - /** - * Completely (re)populate this volume with block and sky lighting data. - * This is expensive and should be avoided. - */ - public void initialize() { - if (lightData == null) return; - - copyLight(getVolume()); - markDirty(); - } - - /** - * Copy block light from the world into this volume. - * - * @param worldVolume the region in the world to copy data from. - */ - public void copyBlock(ImmutableBox worldVolume) { - var pos = new BlockPos.MutableBlockPos(); - - int xShift = box.getMinX(); - int yShift = box.getMinY(); - int zShift = box.getMinZ(); - - worldVolume.forEachContained((x, y, z) -> { - int light = this.level.getBrightness(LightLayer.BLOCK, pos.set(x, y, z)); - - writeBlock(x - xShift, y - yShift, z - zShift, light); - }); - } - - /** - * Copy sky light from the world into this volume. - * - * @param worldVolume the region in the world to copy data from. - */ - public void copySky(ImmutableBox worldVolume) { - var pos = new BlockPos.MutableBlockPos(); - - int xShift = box.getMinX(); - int yShift = box.getMinY(); - int zShift = box.getMinZ(); - - worldVolume.forEachContained((x, y, z) -> { - int light = this.level.getBrightness(LightLayer.SKY, pos.set(x, y, z)); - - writeSky(x - xShift, y - yShift, z - zShift, light); - }); - } - - /** - * Copy all light from the world into this volume. - * - * @param worldVolume the region in the world to copy data from. - */ - public void copyLight(ImmutableBox worldVolume) { - BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); - - int xShift = box.getMinX(); - int yShift = box.getMinY(); - int zShift = box.getMinZ(); - - worldVolume.forEachContained((x, y, z) -> { - pos.set(x, y, z); - - int block = this.level.getBrightness(LightLayer.BLOCK, pos); - int sky = this.level.getBrightness(LightLayer.SKY, pos); - - writeLight(x - xShift, y - yShift, z - zShift, block, sky); - }); - } - - public void delete() { - MemoryUtil.memFree(lightData); - lightData = null; - } - - protected void markDirty() { - // noop - } - - protected void writeLight(int x, int y, int z, int block, int sky) { - byte b = (byte) ((block & 0xF) << 4); - byte s = (byte) ((sky & 0xF) << 4); - - int i = boxPosToBufferIndex(x, y, z); - lightData.put(i, b); - lightData.put(i + 1, s); - } - - protected void writeBlock(int x, int y, int z, int block) { - byte b = (byte) ((block & 0xF) << 4); - - lightData.put(boxPosToBufferIndex(x, y, z), b); - } - - protected void writeSky(int x, int y, int z, int sky) { - byte b = (byte) ((sky & 0xF) << 4); - - lightData.put(boxPosToBufferIndex(x, y, z) + 1, b); - } - - protected int worldPosToBufferIndex(int x, int y, int z) { - x -= box.getMinX(); - y -= box.getMinY(); - z -= box.getMinZ(); - return boxPosToBufferIndex(x, y, z); - } - - protected int boxPosToBufferIndex(int x, int y, int z) { - return (x + box.sizeX() * (y + z * box.sizeY())) * 2; - } - - @Override - public ImmutableBox getVolume() { - return box; - } - - @Override - public boolean isListenerInvalid() { - return lightData == null; - } - } diff --git a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java b/src/main/java/com/jozufozu/flywheel/util/StringUtil.java index 054bf0f43..7af4a9c5f 100644 --- a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java +++ b/src/main/java/com/jozufozu/flywheel/util/StringUtil.java @@ -15,19 +15,33 @@ import java.util.stream.Collectors; import org.lwjgl.system.MemoryUtil; +import com.jozufozu.flywheel.backend.memory.FlwMemoryTracker; + public class StringUtil { - private static final NumberFormat timeFormat = new DecimalFormat("#0.000"); + private static final NumberFormat THREE_DECIMAL_PLACES = new DecimalFormat("#0.000"); + + public static String formatBytes(long bytes) { + if (bytes < 1024) { + return bytes + " B"; + } else if (bytes < 1024 * 1024) { + return THREE_DECIMAL_PLACES.format(bytes / 1024f) + " KiB"; + } else if (bytes < 1024 * 1024 * 1024) { + return THREE_DECIMAL_PLACES.format(bytes / 1024f / 1024f) + " MiB"; + } else { + return THREE_DECIMAL_PLACES.format(bytes / 1024f / 1024f / 1024f) + " GiB"; + } + } public static String formatTime(long ns) { if (ns < 1000) { return ns + " ns"; } else if (ns < 1000000) { - return timeFormat.format(ns / 1000.) + " μs"; + return THREE_DECIMAL_PLACES.format(ns / 1000f) + " μs"; } else if (ns < 1000000000) { - return timeFormat.format(ns / 1000000.) + " ms"; + return THREE_DECIMAL_PLACES.format(ns / 1000000f) + " ms"; } else { - return timeFormat.format(ns / 1000000000.) + " s"; + return THREE_DECIMAL_PLACES.format(ns / 1000000000f) + " s"; } } @@ -56,11 +70,11 @@ public class StringUtil { ((Buffer) bytebuffer).rewind(); return MemoryUtil.memASCII(bytebuffer, i); } catch (IOException ignored) { + // } finally { if (bytebuffer != null) { - MemoryUtil.memFree(bytebuffer); + FlwMemoryTracker.freeBuffer(bytebuffer); } - } return null; @@ -75,12 +89,12 @@ public class StringUtil { } private static ByteBuffer readInputStream(InputStream is) throws IOException { - ByteBuffer bytebuffer = MemoryUtil.memAlloc(8192); + ByteBuffer bytebuffer = FlwMemoryTracker.mallocBuffer(8192); ReadableByteChannel readablebytechannel = Channels.newChannel(is); while (readablebytechannel.read(bytebuffer) != -1) { if (bytebuffer.remaining() == 0) { - bytebuffer = MemoryUtil.memRealloc(bytebuffer, bytebuffer.capacity() * 2); + bytebuffer = FlwMemoryTracker.reallocBuffer(bytebuffer, bytebuffer.capacity() * 2); } } return bytebuffer; @@ -88,7 +102,7 @@ public class StringUtil { private static ByteBuffer readFileInputStream(FileInputStream fileinputstream) throws IOException { FileChannel filechannel = fileinputstream.getChannel(); - ByteBuffer bytebuffer = MemoryUtil.memAlloc((int) filechannel.size() + 1); + ByteBuffer bytebuffer = FlwMemoryTracker.mallocBuffer((int) filechannel.size() + 1); while (filechannel.read(bytebuffer) != -1) { } diff --git a/src/main/java/com/jozufozu/flywheel/util/WorldAttached.java b/src/main/java/com/jozufozu/flywheel/util/WorldAttached.java index cb41e9fd1..93b79a310 100644 --- a/src/main/java/com/jozufozu/flywheel/util/WorldAttached.java +++ b/src/main/java/com/jozufozu/flywheel/util/WorldAttached.java @@ -36,7 +36,16 @@ public class WorldAttached { i.remove(); } else { // Prevent leaks - map.remove(world); + Object attached = map.remove(world); + + // No, *really* prevent leaks + if (attached instanceof AutoCloseable closeable) { + try { + closeable.close(); + } catch (Exception ignored) { + + } + } } } } diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java index 39e6650fb..0089766d2 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java @@ -15,8 +15,8 @@ import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.hardcoded.ModelPart; import com.jozufozu.flywheel.core.model.SimpleLazyModel; import com.jozufozu.flywheel.core.structs.StructTypes; -import com.jozufozu.flywheel.core.structs.model.TransformedPart; import com.jozufozu.flywheel.core.structs.oriented.OrientedPart; +import com.jozufozu.flywheel.core.structs.transformed.TransformedPart; import com.jozufozu.flywheel.util.AnimationTickHolder; import com.mojang.math.Quaternion; import com.mojang.math.Vector3f; diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java index e12f6d37e..d1ae67501 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java @@ -12,7 +12,7 @@ import com.jozufozu.flywheel.core.model.Mesh; import com.jozufozu.flywheel.core.model.Models; import com.jozufozu.flywheel.core.model.SimpleLazyModel; import com.jozufozu.flywheel.core.structs.StructTypes; -import com.jozufozu.flywheel.core.structs.model.TransformedPart; +import com.jozufozu.flywheel.core.structs.transformed.TransformedPart; import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java index cc9aadb8a..cfe63f41d 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java @@ -12,7 +12,7 @@ import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.hardcoded.ModelPart; import com.jozufozu.flywheel.core.model.SimpleLazyModel; import com.jozufozu.flywheel.core.structs.StructTypes; -import com.jozufozu.flywheel.core.structs.model.TransformedPart; +import com.jozufozu.flywheel.core.structs.transformed.TransformedPart; import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java b/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java index d7f362424..60cfa49fa 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java @@ -13,7 +13,7 @@ import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.backend.instancing.effect.Effect; import com.jozufozu.flywheel.core.model.Models; import com.jozufozu.flywheel.core.structs.StructTypes; -import com.jozufozu.flywheel.core.structs.model.TransformedPart; +import com.jozufozu.flywheel.core.structs.transformed.TransformedPart; import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.box.GridAlignedBB;