mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-27 07:26:48 +01:00
Buffer buffers
- Do not map buffers - Strip down GlBuffer, so it only contains upload methods - Remove buffer mapping and copy wrappers - Add subdata wrapper
This commit is contained in:
parent
c61feb1c14
commit
aac12754cc
5 changed files with 56 additions and 171 deletions
|
@ -7,7 +7,6 @@ import java.util.Set;
|
|||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.instance.Instance;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
|
@ -18,7 +17,7 @@ import com.jozufozu.flywheel.backend.gl.array.GlVertexArray;
|
|||
import com.jozufozu.flywheel.backend.gl.array.VertexAttribute;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferUsage;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
|
||||
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||
|
||||
public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I> {
|
||||
private final List<VertexAttribute> instanceAttributes;
|
||||
|
@ -45,7 +44,6 @@ public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I>
|
|||
}
|
||||
|
||||
vbo = new GlBuffer(GlBufferUsage.DYNAMIC_DRAW);
|
||||
vbo.growthFunction(l -> Math.max(l + (long) instanceStride * 16, (long) (l * 1.6)));
|
||||
}
|
||||
|
||||
public void update() {
|
||||
|
@ -59,28 +57,61 @@ public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I>
|
|||
}
|
||||
|
||||
int byteSize = instanceStride * instances.size();
|
||||
if (vbo.ensureCapacity(byteSize)) {
|
||||
// The vbo has moved, so we need to re-bind attributes
|
||||
boundTo.clear();
|
||||
if (needsToGrow(byteSize)) {
|
||||
// TODO: Should this memory block be persistent?
|
||||
var temp = MemoryBlock.malloc(increaseSize(byteSize));
|
||||
|
||||
writeAll(temp.ptr());
|
||||
|
||||
vbo.upload(temp);
|
||||
|
||||
temp.free();
|
||||
} else {
|
||||
writeChanged();
|
||||
}
|
||||
|
||||
try (MappedBuffer buf = vbo.map()) {
|
||||
writeChanged(buf.ptr());
|
||||
|
||||
changed.clear();
|
||||
} catch (Exception e) {
|
||||
Flywheel.LOGGER.error("Error updating InstancedInstancer:", e);
|
||||
}
|
||||
changed.clear();
|
||||
}
|
||||
|
||||
private void writeChanged(long ptr) {
|
||||
private void writeChanged() {
|
||||
changed.forEachSetSpan((startInclusive, endInclusive) -> {
|
||||
var temp = MemoryBlock.malloc((long) instanceStride * (endInclusive - startInclusive + 1));
|
||||
long ptr = temp.ptr();
|
||||
for (int i = startInclusive; i <= endInclusive; i++) {
|
||||
writer.write(ptr + (long) instanceStride * i, instances.get(i));
|
||||
writer.write(ptr, instances.get(i));
|
||||
ptr += instanceStride;
|
||||
}
|
||||
|
||||
vbo.uploadSpan((long) startInclusive * instanceStride, temp);
|
||||
|
||||
temp.free();
|
||||
});
|
||||
}
|
||||
|
||||
private void writeAll(long ptr) {
|
||||
for (I instance : instances) {
|
||||
writer.write(ptr, instance);
|
||||
ptr += instanceStride;
|
||||
}
|
||||
}
|
||||
|
||||
private long increaseSize(long capacity) {
|
||||
return Math.max(capacity + (long) instanceStride * 16, (long) (capacity * 1.6));
|
||||
}
|
||||
|
||||
public boolean needsToGrow(long capacity) {
|
||||
if (capacity < 0) {
|
||||
throw new IllegalArgumentException("Size " + capacity + " < 0");
|
||||
}
|
||||
|
||||
if (capacity == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return capacity > vbo.size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Bind this instancer's vbo to the given vao if it hasn't already been bound.
|
||||
* @param vao The vao to bind to.
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package com.jozufozu.flywheel.backend.gl.buffer;
|
||||
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL31;
|
||||
import org.lwjgl.opengl.GL45C;
|
||||
import org.lwjgl.system.Checks;
|
||||
|
||||
|
@ -15,11 +13,7 @@ public interface Buffer {
|
|||
|
||||
void data(int vbo, long size, long ptr, int glEnum);
|
||||
|
||||
void copyData(int src, int dst, long srcOffset, long dstOffset, long size);
|
||||
|
||||
long mapRange(int handle, int offset, long size, int access);
|
||||
|
||||
void unmap(int handle);
|
||||
void subData(int vbo, long offset, long size, long ptr);
|
||||
|
||||
class DSA implements Buffer {
|
||||
@Override
|
||||
|
@ -33,18 +27,8 @@ public interface Buffer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void copyData(int src, int dst, long srcOffset, long dstOffset, long size) {
|
||||
GL45C.glCopyNamedBufferSubData(src, dst, srcOffset, dstOffset, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long mapRange(int handle, int offset, long size, int access) {
|
||||
return GL45C.nglMapNamedBufferRange(handle, offset, size, access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unmap(int handle) {
|
||||
GL45C.glUnmapNamedBuffer(handle);
|
||||
public void subData(int vbo, long offset, long size, long ptr) {
|
||||
GL45C.nglNamedBufferSubData(vbo, offset, size, ptr);
|
||||
}
|
||||
|
||||
public Buffer fallback() {
|
||||
|
@ -73,23 +57,9 @@ public interface Buffer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void copyData(int src, int dst, long size, long srcOffset, long dstOffset) {
|
||||
GlBufferType.COPY_READ_BUFFER.bind(src);
|
||||
GlBufferType.COPY_WRITE_BUFFER.bind(dst);
|
||||
|
||||
GL31.glCopyBufferSubData(GlBufferType.COPY_READ_BUFFER.glEnum, GlBufferType.COPY_WRITE_BUFFER.glEnum, srcOffset, dstOffset, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long mapRange(int handle, int offset, long size, int access) {
|
||||
GlBufferType.COPY_READ_BUFFER.bind(handle);
|
||||
return GL30.nglMapBufferRange(GlBufferType.COPY_READ_BUFFER.glEnum, 0, size, access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unmap(int handle) {
|
||||
GlBufferType.COPY_READ_BUFFER.bind(handle);
|
||||
GL15.glUnmapBuffer(GlBufferType.COPY_READ_BUFFER.glEnum);
|
||||
public void subData(int vbo, long offset, long size, long ptr) {
|
||||
GlBufferType.COPY_WRITE_BUFFER.bind(vbo);
|
||||
GL15.nglBufferSubData(GlBufferType.COPY_WRITE_BUFFER.glEnum, offset, size, ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,16 @@
|
|||
package com.jozufozu.flywheel.backend.gl.buffer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||
import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker;
|
||||
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.LongUnaryOperator;
|
||||
|
||||
public class GlBuffer extends GlObject {
|
||||
protected final GlBufferUsage usage;
|
||||
/**
|
||||
* The size (in bytes) of the buffer on the GPU.
|
||||
*/
|
||||
protected long size;
|
||||
/**
|
||||
* A mapping to adjust the size of the buffer when allocating.
|
||||
*/
|
||||
protected LongUnaryOperator growthFunction = LongUnaryOperator.identity();
|
||||
|
||||
public GlBuffer() {
|
||||
this(GlBufferUsage.STATIC_DRAW);
|
||||
|
@ -29,63 +21,9 @@ public class GlBuffer extends GlObject {
|
|||
this.usage = usage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the buffer was recreated.
|
||||
*/
|
||||
public boolean ensureCapacity(long capacity) {
|
||||
if (capacity < 0) {
|
||||
throw new IllegalArgumentException("Size " + capacity + " < 0");
|
||||
}
|
||||
|
||||
if (capacity == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
alloc(capacity);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (capacity > size) {
|
||||
realloc(capacity);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void alloc(long capacity) {
|
||||
increaseSize(capacity);
|
||||
Buffer.IMPL.data(handle(), size, MemoryUtil.NULL, usage.glEnum);
|
||||
FlwMemoryTracker._allocGPUMemory(size);
|
||||
}
|
||||
|
||||
private void realloc(long capacity) {
|
||||
FlwMemoryTracker._freeGPUMemory(size);
|
||||
var oldSize = size;
|
||||
increaseSize(capacity);
|
||||
|
||||
int oldHandle = handle();
|
||||
int newHandle = Buffer.IMPL.create();
|
||||
Buffer.IMPL.data(newHandle, size, MemoryUtil.NULL, usage.glEnum);
|
||||
Buffer.IMPL.copyData(oldHandle, newHandle, 0, 0, oldSize);
|
||||
GlStateManager._glDeleteBuffers(oldHandle);
|
||||
handle(newHandle);
|
||||
|
||||
FlwMemoryTracker._allocGPUMemory(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the size of the buffer to at least the given capacity.
|
||||
*/
|
||||
private void increaseSize(long capacity) {
|
||||
size = growthFunction.apply(capacity);
|
||||
}
|
||||
|
||||
public void upload(MemoryBlock memoryBlock) {
|
||||
upload(memoryBlock.ptr(), memoryBlock.size());
|
||||
}
|
||||
|
||||
public void upload(long ptr, long size) {
|
||||
FlwMemoryTracker._freeGPUMemory(this.size);
|
||||
Buffer.IMPL.data(handle(), size, ptr, usage.glEnum);
|
||||
|
@ -93,12 +31,12 @@ public class GlBuffer extends GlObject {
|
|||
FlwMemoryTracker._allocGPUMemory(this.size);
|
||||
}
|
||||
|
||||
public MappedBuffer map() {
|
||||
return new MappedBuffer(handle(), size);
|
||||
public void uploadSpan(long offset, MemoryBlock memoryBlock) {
|
||||
uploadSpan(offset, memoryBlock.ptr(), memoryBlock.size());
|
||||
}
|
||||
|
||||
public void growthFunction(LongUnaryOperator growthFunction) {
|
||||
this.growthFunction = growthFunction;
|
||||
public void uploadSpan(long offset, long ptr, long size) {
|
||||
Buffer.IMPL.subData(handle(), offset, size, ptr);
|
||||
}
|
||||
|
||||
public long size() {
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.gl.buffer;
|
||||
|
||||
import static org.lwjgl.opengl.GL30.GL_MAP_WRITE_BIT;
|
||||
import static org.lwjgl.system.MemoryUtil.NULL;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlError;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlException;
|
||||
|
||||
public class MappedBuffer implements AutoCloseable {
|
||||
private final int glBuffer;
|
||||
private long ptr;
|
||||
|
||||
public MappedBuffer(int glBuffer, long size) {
|
||||
this.glBuffer = glBuffer;
|
||||
|
||||
ptr = Buffer.IMPL.mapRange(glBuffer, 0, size, GL_MAP_WRITE_BIT);
|
||||
|
||||
if (ptr == MemoryUtil.NULL) {
|
||||
throw new GlException(GlError.poll(), "Could not map buffer");
|
||||
}
|
||||
}
|
||||
|
||||
public long ptr() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (ptr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
Buffer.IMPL.unmap(glBuffer);
|
||||
ptr = NULL;
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.gl.buffer;
|
||||
|
||||
import org.lwjgl.opengl.GL15C;
|
||||
|
||||
public enum MappedBufferUsage {
|
||||
READ_ONLY(GL15C.GL_READ_ONLY),
|
||||
WRITE_ONLY(GL15C.GL_WRITE_ONLY),
|
||||
READ_WRITE(GL15C.GL_READ_WRITE),
|
||||
;
|
||||
|
||||
int glEnum;
|
||||
|
||||
MappedBufferUsage(int glEnum) {
|
||||
this.glEnum = glEnum;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue