From a1553b04e72b88e17e9e5db8bddda8b646db7034 Mon Sep 17 00:00:00 2001
From: Jozufozu
Date: Sat, 13 Aug 2022 23:18:44 -0700
Subject: [PATCH] So unsafe it wrapped back around
- Convert buffer mapping to unsafe
- Implement gpu memory tracking
- Fix massive gl resource leak
- Fix GPU memory leak caused by not deleting gl resources
- Fix CPU memory leak caused by not deleting meshes in Models
- Remove PersistentGlBuffer, merge GlBuffer and MappedGlBuffer
---
.../flywheel/api/uniform/UniformProvider.java | 6 +-
.../backend/gl/array/GlVertexArray.java | 2 +-
.../flywheel/backend/gl/buffer/GlBuffer.java | 130 ++++++++++++------
.../backend/gl/buffer/MappedBuffer.java | 30 ++--
.../backend/gl/buffer/MappedGlBuffer.java | 91 ------------
.../backend/gl/buffer/PersistentGlBuffer.java | 124 -----------------
.../backend/instancing/InstanceWorld.java | 6 +-
.../instancing/batching/DrawBuffer.java | 2 +-
.../instancing/instancing/GPUInstancer.java | 11 +-
.../instancing/instancing/MeshPool.java | 19 +--
.../flywheel/core/FullscreenQuad.java | 14 +-
.../jozufozu/flywheel/core/QuadConverter.java | 34 ++---
.../jozufozu/flywheel/core/model/Model.java | 2 +
.../jozufozu/flywheel/core/model/Models.java | 9 ++
.../flywheel/core/model/SimpleLazyModel.java | 5 +
.../flywheel/core/model/TessellatedModel.java | 6 +
.../flywheel/core/uniform/FogProvider.java | 4 +-
.../flywheel/core/uniform/UniformBuffer.java | 17 ++-
.../flywheel/core/uniform/ViewProvider.java | 4 +-
.../jozufozu/flywheel/event/ForgeEvents.java | 3 +-
.../jozufozu/flywheel/util/StringUtil.java | 20 ++-
.../jozufozu/flywheel/util/WorldAttached.java | 11 +-
22 files changed, 191 insertions(+), 359 deletions(-)
delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedGlBuffer.java
delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java
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 2e189f452..62890b521 100644
--- a/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java
+++ b/src/main/java/com/jozufozu/flywheel/api/uniform/UniformProvider.java
@@ -6,13 +6,13 @@ import com.jozufozu.flywheel.core.source.FileResolution;
public abstract class UniformProvider {
- protected ByteBuffer buffer;
+ protected long ptr;
protected Notifier notifier;
public abstract int getSize();
- 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/backend/gl/array/GlVertexArray.java b/src/main/java/com/jozufozu/flywheel/backend/gl/array/GlVertexArray.java
index 3abf7a7d0..69efb178f 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/gl/array/GlVertexArray.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/gl/array/GlVertexArray.java
@@ -5,8 +5,8 @@ import org.lwjgl.opengl.GL32;
import com.jozufozu.flywheel.backend.gl.GlObject;
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
-import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
+import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.mojang.blaze3d.platform.GlStateManager;
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..edfff94d3 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,105 @@
package com.jozufozu.flywheel.backend.gl.buffer;
-import java.nio.ByteBuffer;
+import static org.lwjgl.opengl.GL32.*;
-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 +122,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/instancing/InstanceWorld.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java
index 3962d4d1a..1f48ec759 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java
@@ -27,7 +27,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;
@@ -149,4 +149,8 @@ public class InstanceWorld {
.forEach(entities::add);
}
+ @Override
+ public void close() {
+ delete();
+ }
}
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 8559680ea..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
@@ -89,7 +89,7 @@ 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.
*/
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 95015766a..cfce702fb 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
@@ -3,18 +3,15 @@ package com.jozufozu.flywheel.backend.instancing.instancing;
import java.util.HashSet;
import java.util.Set;
-import org.lwjgl.system.MemoryUtil;
-
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.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
import com.jozufozu.flywheel.core.layout.BufferLayout;
@@ -45,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);
}
@@ -91,8 +88,8 @@ public class GPUInstancer extends AbstractInstancer
buf.clear(clearStart, clearLength);
if (size > 0) {
- final long ptr = MemoryUtil.memAddress(buf.unwrap());
- final int stride = structType.getLayout().getStride();
+ final long ptr = buf.getPtr();
+ final long stride = structType.getLayout().getStride();
final StructWriter writer = structType.getWriter();
for (int i = 0; i < size; i++) {
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 a5d7b6051..c43a49fc9 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;
@@ -10,16 +9,14 @@ import java.util.Set;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.opengl.GL32;
-import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
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.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.jozufozu.flywheel.core.model.Mesh;
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
@@ -58,7 +55,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);
}
@@ -141,13 +138,13 @@ public class MeshPool {
private void uploadAll() {
try (MappedBuffer mapped = vbo.map()) {
- ByteBuffer buffer = mapped.unwrap();
+ long ptr = mapped.getPtr();
int byteIndex = 0;
for (BufferedMesh model : allBuffered) {
model.byteIndex = byteIndex;
- model.buffer(buffer);
+ model.buffer(ptr);
byteIndex += model.mesh.size();
}
@@ -159,7 +156,7 @@ public class MeshPool {
private void uploadPending() {
try (MappedBuffer mapped = vbo.map()) {
- ByteBuffer buffer = mapped.unwrap();
+ long buffer = mapped.getPtr();
for (BufferedMesh model : pendingUpload) {
model.buffer(buffer);
}
@@ -240,10 +237,8 @@ public class MeshPool {
this.deleted = true;
}
- private void buffer(ByteBuffer buffer) {
- buffer.position((int) this.byteIndex);
- long ptr = MemoryUtil.memAddress(buffer);
- this.mesh.write(ptr);
+ 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/core/FullscreenQuad.java b/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java
index c3282c2ae..79b49df58 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.backend.gl.buffer.GlBuffer;
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..93427f829 100644
--- a/src/main/java/com/jozufozu/flywheel/core/QuadConverter.java
+++ b/src/main/java/com/jozufozu/flywheel/core/QuadConverter.java
@@ -1,7 +1,5 @@
package com.jozufozu.flywheel.core;
-import java.nio.ByteBuffer;
-
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.system.MemoryUtil;
@@ -9,7 +7,7 @@ import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.backend.gl.GlNumericType;
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.gl.buffer.GlBuffer;
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/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/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/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/uniform/FogProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java
index 9bea01220..29873074b 100644
--- a/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java
+++ b/src/main/java/com/jozufozu/flywheel/core/uniform/FogProvider.java
@@ -15,14 +15,12 @@ public class FogProvider extends UniformProvider {
}
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/UniformBuffer.java b/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java
index 068fbc4c0..e1c88b815 100644
--- a/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java
+++ b/src/main/java/com/jozufozu/flywheel/core/uniform/UniformBuffer.java
@@ -1,6 +1,5 @@
package com.jozufozu.flywheel.core.uniform;
-import java.nio.ByteBuffer;
import java.util.BitSet;
import java.util.Collection;
import java.util.List;
@@ -11,8 +10,8 @@ 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.GlBufferType;
-import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer;
-import com.jozufozu.flywheel.backend.memory.FlwMemoryTracker;
+import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
+import com.jozufozu.flywheel.backend.memory.MemoryBlock;
import com.jozufozu.flywheel.core.ComponentRegistry;
import com.jozufozu.flywheel.util.RenderMath;
@@ -33,13 +32,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 +56,7 @@ public class UniformBuffer {
allocatedProviders = builder.build();
- data = FlwMemoryTracker.mallocBuffer(totalBytes);
+ data = MemoryBlock.mallocTracked(totalBytes);
changedBytes = new BitSet(totalBytes);
for (Allocated p : allocatedProviders) {
@@ -108,8 +107,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 1d5535b6d..437b5cdcd 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);
-
MatrixWrite.writeUnsafe(vp, ptr);
MemoryUtil.memPutFloat(ptr + 64, camX);
MemoryUtil.memPutFloat(ptr + 68, camY);
diff --git a/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java b/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java
index 26bc79290..793f519ca 100644
--- a/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java
+++ b/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java
@@ -7,6 +7,7 @@ import com.jozufozu.flywheel.backend.Backend;
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,7 +25,7 @@ public class ForgeEvents {
InstancedRenderDispatcher.getDebugString(debug);
- debug.add("Memory Usage: CPU: " + FlwMemoryTracker.getCPUMemory() / 1024 + "KiB GPU: " + FlwMemoryTracker.getGPUMemory() / 1024 + "KiB");
+ debug.add("Memory Usage: CPU: " + StringUtil.formatBytes(FlwMemoryTracker.getCPUMemory()) + ", GPU: " + StringUtil.formatBytes(FlwMemoryTracker.getGPUMemory()));
}
}
diff --git a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java b/src/main/java/com/jozufozu/flywheel/util/StringUtil.java
index 4b7049b74..cdf8c6952 100644
--- a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java
+++ b/src/main/java/com/jozufozu/flywheel/util/StringUtil.java
@@ -19,17 +19,29 @@ 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) + " KB";
+ } else if (bytes < 1024 * 1024 * 1024) {
+ return THREE_DECIMAL_PLACES.format(bytes / 1024f / 1024f) + " MB";
+ } else {
+ return THREE_DECIMAL_PLACES.format(bytes / 1024f / 1024f / 1024f) + " GB";
+ }
+ }
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";
}
}
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) {
+
+ }
+ }
}
}
}