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;
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);
}
}

View file

@ -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());
}

View file

@ -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) {

View file

@ -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;
}

View file

@ -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<D extends InstanceData> extends AbstractInstancer<D> {
@ -26,7 +26,6 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
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<D extends InstanceData> extends AbstractInstancer<D> {
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<D extends InstanceData> extends AbstractInstancer<D> {
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<D extends InstanceData> extends AbstractInstancer<D> {
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<D extends InstanceData> extends AbstractInstancer<D> {
if (size <= 0) return;
try (MappedBuffer mapped = instanceVBO.getBuffer(0, glBufferSize)) {
try (MappedBuffer mapped = instanceVBO.getBuffer()) {
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 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<D> writer = instancedType.getWriter(buffer);
for (D datum : data) {
writer.write(datum);

View file

@ -59,7 +59,10 @@ public class InstancedMaterialGroup<P extends WorldProgram> 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<P extends WorldProgram> implements MaterialG
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.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();

View file

@ -25,7 +25,6 @@ public class ModelPool implements ModelAllocator {
private final List<PooledModel> 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);

View file

@ -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);

View file

@ -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);