mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-27 07:26:48 +01:00
GlBuffer tracks its size
- GlVertexArray#enableArrays
This commit is contained in:
parent
1594c56df2
commit
21d0db1364
10 changed files with 93 additions and 61 deletions
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue