GlBuffer tracks its size

- GlVertexArray#enableArrays
This commit is contained in:
Jozufozu 2021-12-22 14:39:34 -08:00
parent 1594c56df2
commit 21d0db1364
10 changed files with 93 additions and 61 deletions

View file

@ -1,5 +1,6 @@
package com.jozufozu.flywheel.backend.gl; package com.jozufozu.flywheel.backend.gl;
import com.jozufozu.flywheel.util.AttribUtil;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
public class GlVertexArray extends GlObject { public class GlVertexArray extends GlObject {
@ -18,4 +19,8 @@ public class GlVertexArray extends GlObject {
protected void deleteInternal(int handle) { protected void deleteInternal(int handle) {
GlStateManager._glDeleteVertexArrays(handle); GlStateManager._glDeleteVertexArrays(handle);
} }
public void enableArrays(int count) {
AttribUtil.enableArrays(count);
}
} }

View file

@ -9,13 +9,6 @@ import com.jozufozu.flywheel.backend.gl.GlObject;
public abstract class GlBuffer extends GlObject { public abstract class GlBuffer extends GlObject {
protected final GlBufferType type;
public GlBuffer(GlBufferType type) {
_create();
this.type = type;
}
/** /**
* Request a Persistent mapped buffer. * Request a Persistent mapped buffer.
* *
@ -35,10 +28,63 @@ public abstract class GlBuffer extends GlObject {
} }
} }
public GlBufferType getBufferTarget() { protected final GlBufferType type;
return 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() { public void bind() {
type.bind(handle()); type.bind(handle());
} }
@ -47,16 +93,6 @@ public abstract class GlBuffer extends GlObject {
type.unbind(); 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() { protected void _create() {
setHandle(GL20.glGenBuffers()); setHandle(GL20.glGenBuffers());
} }

View file

@ -21,7 +21,7 @@ public class MappedGlBuffer extends GlBuffer implements Mappable {
this.usage = usage; this.usage = usage;
} }
public void alloc(long size) { protected void alloc(long size) {
GL15.glBufferData(type.glEnum, size, usage.glEnum); 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); 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); ByteBuffer byteBuffer = GL30.glMapBufferRange(type.glEnum, offset, length, GL30.GL_MAP_WRITE_BIT);
if (byteBuffer == null) { if (byteBuffer == null) {

View file

@ -35,7 +35,7 @@ public class PersistentGlBuffer extends GlBuffer implements Mappable {
} }
@Override @Override
public void alloc(long size) { protected void alloc(long size) {
this.size = size; this.size = size;
if (buffer != null) { if (buffer != null) {
@ -71,11 +71,11 @@ public class PersistentGlBuffer extends GlBuffer implements Mappable {
} }
@Override @Override
public MappedBuffer getBuffer(int offset, int length) { public MappedBuffer getBuffer(long offset, long length) {
fence.waitSync(); fence.waitSync();
buffer.position(offset); buffer.position((int) offset);
return buffer; return buffer;
} }

View file

@ -1,5 +1,7 @@
package com.jozufozu.flywheel.backend.instancing.instancing; package com.jozufozu.flywheel.backend.instancing.instancing;
import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.InstanceData; import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.struct.Instanced; 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.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer; 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.instancing.AbstractInstancer;
import com.jozufozu.flywheel.backend.model.BufferedModel; import com.jozufozu.flywheel.backend.model.BufferedModel;
import com.jozufozu.flywheel.backend.model.ModelAllocator; import com.jozufozu.flywheel.backend.model.ModelAllocator;
import com.jozufozu.flywheel.core.model.Model; import com.jozufozu.flywheel.core.model.Model;
import com.jozufozu.flywheel.util.AttribUtil;
public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> { public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
@ -26,7 +26,6 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
private BufferedModel model; private BufferedModel model;
private GlVertexArray vao; private GlVertexArray vao;
private GlBuffer instanceVBO; private GlBuffer instanceVBO;
private int glBufferSize = -1;
private int glInstanceCount = 0; private int glInstanceCount = 0;
private boolean deleted; private boolean deleted;
private boolean initialized; private boolean initialized;
@ -49,14 +48,11 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
if (invalid()) return; if (invalid()) return;
vao.bind(); vao.bind();
GlError.pollAndThrow(() -> modelData.name() + "_bind");
renderSetup(); renderSetup();
GlError.pollAndThrow(() -> modelData.name() + "_setup");
if (glInstanceCount > 0) { if (glInstanceCount > 0) {
model.drawInstances(glInstanceCount); model.drawInstances(glInstanceCount);
GlError.pollAndThrow(() -> modelData.name() + "_draw");
} }
// persistent mapping sync point // persistent mapping sync point
@ -83,7 +79,8 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
vao.bind(); vao.bind();
instanceVBO = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER); 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() { public boolean isInitialized() {
@ -135,10 +132,10 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
private void clearBufferTail() { private void clearBufferTail() {
int size = data.size(); int size = data.size();
final int offset = size * instanceFormat.getStride(); final int offset = size * instanceFormat.getStride();
final int length = glBufferSize - offset; final long length = instanceVBO.getCapacity() - offset;
if (length > 0) { if (length > 0) {
try (MappedBuffer buf = instanceVBO.getBuffer(offset, length)) { try (MappedBuffer buf = instanceVBO.getBuffer(offset, length)) {
buf.putByteArray(new byte[length]); MemoryUtil.memSet(MemoryUtil.memAddress(buf.unwrap()), 0, length);
} catch (Exception e) { } catch (Exception e) {
Flywheel.log.error("Error clearing buffer tail:", e); Flywheel.log.error("Error clearing buffer tail:", e);
} }
@ -150,7 +147,7 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
if (size <= 0) return; if (size <= 0) return;
try (MappedBuffer mapped = instanceVBO.getBuffer(0, glBufferSize)) { try (MappedBuffer mapped = instanceVBO.getBuffer()) {
final StructWriter<D> writer = instancedType.getWriter(mapped); final StructWriter<D> writer = instancedType.getWriter(mapped);
@ -170,11 +167,9 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
int size = this.data.size(); int size = this.data.size();
int stride = instanceFormat.getStride(); int stride = instanceFormat.getStride();
int requiredSize = size * stride; int requiredSize = size * stride;
if (requiredSize > glBufferSize) { if (instanceVBO.ensureCapacity(requiredSize)) {
glBufferSize = requiredSize + stride * 16;
instanceVBO.alloc(glBufferSize);
try (MappedBuffer buffer = instanceVBO.getBuffer(0, glBufferSize)) { try (MappedBuffer buffer = instanceVBO.getBuffer()) {
StructWriter<D> writer = instancedType.getWriter(buffer); StructWriter<D> writer = instancedType.getWriter(buffer);
for (D datum : data) { for (D datum : data) {
writer.write(datum); writer.write(datum);

View file

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

View file

@ -36,12 +36,11 @@ public class ArrayModelRenderer extends ModelRenderer {
vao = new GlVertexArray(); vao = new GlVertexArray();
vao.bind(); vao.bind();
vao.enableArrays(this.model.getAttributeCount());
// bind the model's vbo to our vao // bind the model's vbo to our vao
this.model.setupState(); this.model.setupState();
AttribUtil.enableArrays(this.model.getAttributeCount());
GlVertexArray.unbind(); GlVertexArray.unbind();
this.model.clearState(); this.model.clearState();

View file

@ -25,7 +25,6 @@ public class ModelPool implements ModelAllocator {
private final List<PooledModel> pendingUpload = new ArrayList<>(); private final List<PooledModel> pendingUpload = new ArrayList<>();
private final GlBuffer vbo; private final GlBuffer vbo;
private int bufferSize;
private int vertices; private int vertices;
@ -34,12 +33,13 @@ public class ModelPool implements ModelAllocator {
public ModelPool(VertexType vertexType, int initialSize) { public ModelPool(VertexType vertexType, int initialSize) {
this.vertexType = vertexType; this.vertexType = vertexType;
bufferSize = vertexType.getStride() * initialSize; int stride = vertexType.getStride();
vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER); vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER);
vbo.bind(); vbo.bind();
vbo.alloc(bufferSize); vbo.ensureCapacity((long) stride * initialSize);
vbo.setGrowthMargin(stride * 64);
vbo.unbind(); vbo.unbind();
} }
@ -104,19 +104,11 @@ public class ModelPool implements ModelAllocator {
* @return true if the buffer was reallocated * @return true if the buffer was reallocated
*/ */
private boolean realloc() { private boolean realloc() {
int neededSize = vertices * vertexType.getStride(); return vbo.ensureCapacity((long) vertices * vertexType.getStride());
if (neededSize > bufferSize) {
bufferSize = neededSize + 128;
vbo.alloc(bufferSize);
return true;
}
return false;
} }
private void uploadAll() { private void uploadAll() {
try (MappedBuffer buffer = vbo.getBuffer(0, bufferSize)) { try (MappedBuffer buffer = vbo.getBuffer()) {
VertexWriter writer = vertexType.createWriter(buffer.unwrap()); VertexWriter writer = vertexType.createWriter(buffer.unwrap());
int vertices = 0; int vertices = 0;
@ -134,7 +126,7 @@ public class ModelPool implements ModelAllocator {
} }
private void uploadPending() { private void uploadPending() {
try (MappedBuffer buffer = vbo.getBuffer(0, bufferSize)) { try (MappedBuffer buffer = vbo.getBuffer()) {
VertexWriter writer = vertexType.createWriter(buffer.unwrap()); VertexWriter writer = vertexType.createWriter(buffer.unwrap());
for (PooledModel model : pendingUpload) { for (PooledModel model : pendingUpload) {
buffer(writer, model); buffer(writer, model);

View file

@ -29,10 +29,10 @@ public class VBOModel implements BufferedModel {
vbo.bind(); vbo.bind();
// allocate the buffer on the gpu // 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. // mirror it in system memory, so we can write to it, and upload our model.
try (MappedBuffer buffer = vbo.getBuffer(0, model.size())) { try (MappedBuffer buffer = vbo.getBuffer()) {
model.writeInto(buffer.unwrap()); model.writeInto(buffer.unwrap());
} catch (Exception e) { } catch (Exception e) {
Flywheel.log.error(String.format("Error uploading model '%s':", model.name()), e); Flywheel.log.error(String.format("Error uploading model '%s':", model.name()), e);

View file

@ -32,8 +32,8 @@ public class FullscreenQuad {
private FullscreenQuad() { private FullscreenQuad() {
vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER); vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER);
vbo.bind(); vbo.bind();
vbo.alloc(bufferSize); vbo.ensureCapacity(bufferSize);
try (MappedBuffer buffer = vbo.getBuffer(0, bufferSize)) { try (MappedBuffer buffer = vbo.getBuffer()) {
buffer.putFloatArray(vertices); buffer.putFloatArray(vertices);
} catch (Exception e) { } catch (Exception e) {
Flywheel.log.error("Could not create fullscreen quad.", e); Flywheel.log.error("Could not create fullscreen quad.", e);