From 80d41a76af5e2ee9cc2d33737e30da472fb81788 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Wed, 22 Dec 2021 14:39:34 -0800 Subject: [PATCH] GlBuffer tracks its size - GlVertexArray#enableArrays --- .../flywheel/backend/gl/GlVertexArray.java | 5 ++ .../flywheel/backend/gl/buffer/GlBuffer.java | 74 ++++++++++++++----- .../backend/gl/buffer/MappedGlBuffer.java | 4 +- .../backend/gl/buffer/PersistentGlBuffer.java | 6 +- .../instancing/instancing/GPUInstancer.java | 23 +++--- .../instancing/InstancedMaterialGroup.java | 9 ++- .../backend/model/ArrayModelRenderer.java | 3 +- .../flywheel/backend/model/ModelPool.java | 20 ++--- .../flywheel/backend/model/VBOModel.java | 6 +- .../flywheel/core/FullscreenQuad.java | 4 +- 10 files changed, 93 insertions(+), 61 deletions(-) diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java b/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java index 9053539e6..c75e1e117 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java @@ -1,5 +1,6 @@ package com.jozufozu.flywheel.backend.gl; +import com.jozufozu.flywheel.util.AttribUtil; import com.mojang.blaze3d.platform.GlStateManager; public class GlVertexArray extends GlObject { @@ -18,4 +19,8 @@ public class GlVertexArray extends GlObject { protected void deleteInternal(int handle) { GlStateManager._glDeleteVertexArrays(handle); } + + public void enableArrays(int count) { + AttribUtil.enableArrays(count); + } } 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 f764f1dec..2c2e31e25 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 @@ -9,13 +9,6 @@ import com.jozufozu.flywheel.backend.gl.GlObject; public abstract class GlBuffer extends GlObject { - protected final GlBufferType type; - - public GlBuffer(GlBufferType type) { - _create(); - this.type = type; - } - /** * Request a Persistent mapped buffer. * @@ -35,10 +28,63 @@ public abstract class GlBuffer extends GlObject { } } - public GlBufferType getBufferTarget() { - return type; + protected final GlBufferType type; + + /** + * The size (in bytes) of the buffer on the GPU. + */ + protected long capacity; + + /** + * How much extra room to give the buffer when we reallocate. + */ + protected int growthMargin; + + public GlBuffer(GlBufferType type) { + _create(); + this.type = type; } + public void setGrowthMargin(int growthMargin) { + this.growthMargin = growthMargin; + } + + public long getCapacity() { + return capacity; + } + + public MappedBuffer getBuffer() { + return getBuffer(0, capacity); + } + + public abstract MappedBuffer getBuffer(long offset, long length); + + /** + * Ensure that the buffer has at least enough room to store size bytes. + * + * @return true if the buffer grew. + */ + public boolean ensureCapacity(long size) { + if (size > capacity) { + capacity = size + growthMargin; + alloc(capacity); + return true; + } + + return false; + } + + /** + * Call this after all draw calls using this buffer are complete. + */ + public void doneForThisFrame() { + + } + + protected abstract void alloc(long size); + + public abstract void upload(ByteBuffer directBuffer); + public void bind() { type.bind(handle()); } @@ -47,16 +93,6 @@ public abstract class GlBuffer extends GlObject { type.unbind(); } - public void doneForThisFrame() { - - } - - public abstract void alloc(long size); - - public abstract void upload(ByteBuffer directBuffer); - - public abstract MappedBuffer getBuffer(int offset, int length); - protected void _create() { setHandle(GL20.glGenBuffers()); } 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 index 8df8ebea0..aef6e8ce5 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedGlBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedGlBuffer.java @@ -21,7 +21,7 @@ public class MappedGlBuffer extends GlBuffer implements Mappable { this.usage = usage; } - public void alloc(long size) { + protected void alloc(long size) { GL15.glBufferData(type.glEnum, size, usage.glEnum); } @@ -29,7 +29,7 @@ public class MappedGlBuffer extends GlBuffer implements Mappable { GL15.glBufferData(type.glEnum, directBuffer, usage.glEnum); } - public MappedBuffer getBuffer(int offset, int length) { + public MappedBuffer getBuffer(long offset, long length) { ByteBuffer byteBuffer = GL30.glMapBufferRange(type.glEnum, offset, length, GL30.GL_MAP_WRITE_BIT); if (byteBuffer == null) { 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 index 86fb3adbf..79f6148ef 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java @@ -35,7 +35,7 @@ public class PersistentGlBuffer extends GlBuffer implements Mappable { } @Override - public void alloc(long size) { + protected void alloc(long size) { this.size = size; if (buffer != null) { @@ -71,11 +71,11 @@ public class PersistentGlBuffer extends GlBuffer implements Mappable { } @Override - public MappedBuffer getBuffer(int offset, int length) { + public MappedBuffer getBuffer(long offset, long length) { fence.waitSync(); - buffer.position(offset); + buffer.position((int) offset); return 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 ed92586cf..ae9cb845d 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 @@ -1,5 +1,7 @@ package com.jozufozu.flywheel.backend.instancing.instancing; +import org.lwjgl.system.MemoryUtil; + import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.InstanceData; import com.jozufozu.flywheel.api.struct.Instanced; @@ -10,12 +12,10 @@ import com.jozufozu.flywheel.core.layout.BufferLayout; 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.error.GlError; import com.jozufozu.flywheel.backend.instancing.AbstractInstancer; import com.jozufozu.flywheel.backend.model.BufferedModel; import com.jozufozu.flywheel.backend.model.ModelAllocator; import com.jozufozu.flywheel.core.model.Model; -import com.jozufozu.flywheel.util.AttribUtil; public class GPUInstancer extends AbstractInstancer { @@ -26,7 +26,6 @@ public class GPUInstancer extends AbstractInstancer { private BufferedModel model; private GlVertexArray vao; private GlBuffer instanceVBO; - private int glBufferSize = -1; private int glInstanceCount = 0; private boolean deleted; private boolean initialized; @@ -49,14 +48,11 @@ public class GPUInstancer extends AbstractInstancer { if (invalid()) return; vao.bind(); - GlError.pollAndThrow(() -> modelData.name() + "_bind"); renderSetup(); - GlError.pollAndThrow(() -> modelData.name() + "_setup"); if (glInstanceCount > 0) { model.drawInstances(glInstanceCount); - GlError.pollAndThrow(() -> modelData.name() + "_draw"); } // persistent mapping sync point @@ -83,7 +79,8 @@ public class GPUInstancer extends AbstractInstancer { vao.bind(); instanceVBO = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER); - AttribUtil.enableArrays(model.getAttributeCount() + instanceFormat.getAttributeCount()); + instanceVBO.setGrowthMargin(instanceFormat.getStride() * 16); + vao.enableArrays(model.getAttributeCount() + instanceFormat.getAttributeCount()); } public boolean isInitialized() { @@ -135,10 +132,10 @@ public class GPUInstancer extends AbstractInstancer { private void clearBufferTail() { int size = data.size(); final int offset = size * instanceFormat.getStride(); - final int length = glBufferSize - offset; + final long length = instanceVBO.getCapacity() - offset; if (length > 0) { try (MappedBuffer buf = instanceVBO.getBuffer(offset, length)) { - buf.putByteArray(new byte[length]); + MemoryUtil.memSet(MemoryUtil.memAddress(buf.unwrap()), 0, length); } catch (Exception e) { Flywheel.log.error("Error clearing buffer tail:", e); } @@ -150,7 +147,7 @@ public class GPUInstancer extends AbstractInstancer { if (size <= 0) return; - try (MappedBuffer mapped = instanceVBO.getBuffer(0, glBufferSize)) { + try (MappedBuffer mapped = instanceVBO.getBuffer()) { final StructWriter writer = instancedType.getWriter(mapped); @@ -170,11 +167,9 @@ public class GPUInstancer extends AbstractInstancer { int size = this.data.size(); int stride = instanceFormat.getStride(); int requiredSize = size * stride; - if (requiredSize > glBufferSize) { - glBufferSize = requiredSize + stride * 16; - instanceVBO.alloc(glBufferSize); + if (instanceVBO.ensureCapacity(requiredSize)) { - try (MappedBuffer buffer = instanceVBO.getBuffer(0, glBufferSize)) { + try (MappedBuffer buffer = instanceVBO.getBuffer()) { StructWriter writer = instancedType.getWriter(buffer); for (D datum : data) { writer.write(datum); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java index f0a432b2d..8938686f1 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java @@ -59,7 +59,10 @@ public class InstancedMaterialGroup

implements MaterialG .values(); // initialize all uninitialized instancers... - instancers.forEach(GPUInstancer::init); + for (GPUInstancer gpuInstancer : instancers) { + gpuInstancer.init(); + } + if (material.allocator instanceof ModelPool pool) { // ...and then flush the model arena in case anything was marked for upload pool.flush(); @@ -74,7 +77,9 @@ public class InstancedMaterialGroup

implements MaterialG setup(program); - instancers.forEach(GPUInstancer::render); + for (GPUInstancer instancer : instancers) { + instancer.render(); + } } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/ArrayModelRenderer.java b/src/main/java/com/jozufozu/flywheel/backend/model/ArrayModelRenderer.java index 97cfc5da7..0a5185bd9 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/ArrayModelRenderer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/model/ArrayModelRenderer.java @@ -36,12 +36,11 @@ public class ArrayModelRenderer extends ModelRenderer { vao = new GlVertexArray(); vao.bind(); + vao.enableArrays(this.model.getAttributeCount()); // bind the model's vbo to our vao this.model.setupState(); - AttribUtil.enableArrays(this.model.getAttributeCount()); - GlVertexArray.unbind(); this.model.clearState(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java b/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java index c93fe945c..feb5815ab 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java @@ -25,7 +25,6 @@ public class ModelPool implements ModelAllocator { private final List pendingUpload = new ArrayList<>(); private final GlBuffer vbo; - private int bufferSize; private int vertices; @@ -34,12 +33,13 @@ public class ModelPool implements ModelAllocator { public ModelPool(VertexType vertexType, int initialSize) { this.vertexType = vertexType; - bufferSize = vertexType.getStride() * initialSize; + int stride = vertexType.getStride(); vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER); vbo.bind(); - vbo.alloc(bufferSize); + vbo.ensureCapacity((long) stride * initialSize); + vbo.setGrowthMargin(stride * 64); vbo.unbind(); } @@ -104,19 +104,11 @@ public class ModelPool implements ModelAllocator { * @return true if the buffer was reallocated */ private boolean realloc() { - int neededSize = vertices * vertexType.getStride(); - if (neededSize > bufferSize) { - bufferSize = neededSize + 128; - vbo.alloc(bufferSize); - - return true; - } - - return false; + return vbo.ensureCapacity((long) vertices * vertexType.getStride()); } private void uploadAll() { - try (MappedBuffer buffer = vbo.getBuffer(0, bufferSize)) { + try (MappedBuffer buffer = vbo.getBuffer()) { VertexWriter writer = vertexType.createWriter(buffer.unwrap()); int vertices = 0; @@ -134,7 +126,7 @@ public class ModelPool implements ModelAllocator { } private void uploadPending() { - try (MappedBuffer buffer = vbo.getBuffer(0, bufferSize)) { + try (MappedBuffer buffer = vbo.getBuffer()) { VertexWriter writer = vertexType.createWriter(buffer.unwrap()); for (PooledModel model : pendingUpload) { buffer(writer, model); diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/VBOModel.java b/src/main/java/com/jozufozu/flywheel/backend/model/VBOModel.java index fee075c2a..06c8d1066 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/VBOModel.java +++ b/src/main/java/com/jozufozu/flywheel/backend/model/VBOModel.java @@ -29,10 +29,10 @@ public class VBOModel implements BufferedModel { vbo.bind(); // allocate the buffer on the gpu - vbo.alloc(model.size()); + vbo.ensureCapacity(model.size()); - // mirror it in system memory so we can write to it, and upload our model. - try (MappedBuffer buffer = vbo.getBuffer(0, model.size())) { + // mirror it in system memory, so we can write to it, and upload our model. + try (MappedBuffer buffer = vbo.getBuffer()) { model.writeInto(buffer.unwrap()); } catch (Exception e) { Flywheel.log.error(String.format("Error uploading model '%s':", model.name()), e); diff --git a/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java b/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java index 1436dab6c..d319a2656 100644 --- a/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java +++ b/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java @@ -32,8 +32,8 @@ public class FullscreenQuad { private FullscreenQuad() { vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER); vbo.bind(); - vbo.alloc(bufferSize); - try (MappedBuffer buffer = vbo.getBuffer(0, bufferSize)) { + vbo.ensureCapacity(bufferSize); + try (MappedBuffer buffer = vbo.getBuffer()) { buffer.putFloatArray(vertices); } catch (Exception e) { Flywheel.log.error("Could not create fullscreen quad.", e);