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 org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.Flywheel;
|
|
||||||
import com.jozufozu.flywheel.api.context.Context;
|
import com.jozufozu.flywheel.api.context.Context;
|
||||||
import com.jozufozu.flywheel.api.instance.Instance;
|
import com.jozufozu.flywheel.api.instance.Instance;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
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.array.VertexAttribute;
|
||||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferUsage;
|
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> {
|
public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I> {
|
||||||
private final List<VertexAttribute> instanceAttributes;
|
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 = new GlBuffer(GlBufferUsage.DYNAMIC_DRAW);
|
||||||
vbo.growthFunction(l -> Math.max(l + (long) instanceStride * 16, (long) (l * 1.6)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update() {
|
public void update() {
|
||||||
|
@ -59,28 +57,61 @@ public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I>
|
||||||
}
|
}
|
||||||
|
|
||||||
int byteSize = instanceStride * instances.size();
|
int byteSize = instanceStride * instances.size();
|
||||||
if (vbo.ensureCapacity(byteSize)) {
|
if (needsToGrow(byteSize)) {
|
||||||
// The vbo has moved, so we need to re-bind attributes
|
// TODO: Should this memory block be persistent?
|
||||||
boundTo.clear();
|
var temp = MemoryBlock.malloc(increaseSize(byteSize));
|
||||||
|
|
||||||
|
writeAll(temp.ptr());
|
||||||
|
|
||||||
|
vbo.upload(temp);
|
||||||
|
|
||||||
|
temp.free();
|
||||||
|
} else {
|
||||||
|
writeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
try (MappedBuffer buf = vbo.map()) {
|
changed.clear();
|
||||||
writeChanged(buf.ptr());
|
|
||||||
|
|
||||||
changed.clear();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Flywheel.LOGGER.error("Error updating InstancedInstancer:", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeChanged(long ptr) {
|
private void writeChanged() {
|
||||||
changed.forEachSetSpan((startInclusive, endInclusive) -> {
|
changed.forEachSetSpan((startInclusive, endInclusive) -> {
|
||||||
|
var temp = MemoryBlock.malloc((long) instanceStride * (endInclusive - startInclusive + 1));
|
||||||
|
long ptr = temp.ptr();
|
||||||
for (int i = startInclusive; i <= endInclusive; i++) {
|
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.
|
* Bind this instancer's vbo to the given vao if it hasn't already been bound.
|
||||||
* @param vao The vao to bind to.
|
* @param vao The vao to bind to.
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package com.jozufozu.flywheel.backend.gl.buffer;
|
package com.jozufozu.flywheel.backend.gl.buffer;
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL15;
|
import org.lwjgl.opengl.GL15;
|
||||||
import org.lwjgl.opengl.GL30;
|
|
||||||
import org.lwjgl.opengl.GL31;
|
|
||||||
import org.lwjgl.opengl.GL45C;
|
import org.lwjgl.opengl.GL45C;
|
||||||
import org.lwjgl.system.Checks;
|
import org.lwjgl.system.Checks;
|
||||||
|
|
||||||
|
@ -15,11 +13,7 @@ public interface Buffer {
|
||||||
|
|
||||||
void data(int vbo, long size, long ptr, int glEnum);
|
void data(int vbo, long size, long ptr, int glEnum);
|
||||||
|
|
||||||
void copyData(int src, int dst, long srcOffset, long dstOffset, long size);
|
void subData(int vbo, long offset, long size, long ptr);
|
||||||
|
|
||||||
long mapRange(int handle, int offset, long size, int access);
|
|
||||||
|
|
||||||
void unmap(int handle);
|
|
||||||
|
|
||||||
class DSA implements Buffer {
|
class DSA implements Buffer {
|
||||||
@Override
|
@Override
|
||||||
|
@ -33,18 +27,8 @@ public interface Buffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void copyData(int src, int dst, long srcOffset, long dstOffset, long size) {
|
public void subData(int vbo, long offset, long size, long ptr) {
|
||||||
GL45C.glCopyNamedBufferSubData(src, dst, srcOffset, dstOffset, size);
|
GL45C.nglNamedBufferSubData(vbo, offset, size, ptr);
|
||||||
}
|
|
||||||
|
|
||||||
@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 Buffer fallback() {
|
public Buffer fallback() {
|
||||||
|
@ -73,23 +57,9 @@ public interface Buffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void copyData(int src, int dst, long size, long srcOffset, long dstOffset) {
|
public void subData(int vbo, long offset, long size, long ptr) {
|
||||||
GlBufferType.COPY_READ_BUFFER.bind(src);
|
GlBufferType.COPY_WRITE_BUFFER.bind(vbo);
|
||||||
GlBufferType.COPY_WRITE_BUFFER.bind(dst);
|
GL15.nglBufferSubData(GlBufferType.COPY_WRITE_BUFFER.glEnum, offset, size, ptr);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,16 @@
|
||||||
package com.jozufozu.flywheel.backend.gl.buffer;
|
package com.jozufozu.flywheel.backend.gl.buffer;
|
||||||
|
|
||||||
import org.lwjgl.system.MemoryUtil;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.gl.GlObject;
|
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||||
import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker;
|
import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker;
|
||||||
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||||
import com.mojang.blaze3d.platform.GlStateManager;
|
import com.mojang.blaze3d.platform.GlStateManager;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongUnaryOperator;
|
|
||||||
|
|
||||||
public class GlBuffer extends GlObject {
|
public class GlBuffer extends GlObject {
|
||||||
protected final GlBufferUsage usage;
|
protected final GlBufferUsage usage;
|
||||||
/**
|
/**
|
||||||
* The size (in bytes) of the buffer on the GPU.
|
* The size (in bytes) of the buffer on the GPU.
|
||||||
*/
|
*/
|
||||||
protected long size;
|
protected long size;
|
||||||
/**
|
|
||||||
* A mapping to adjust the size of the buffer when allocating.
|
|
||||||
*/
|
|
||||||
protected LongUnaryOperator growthFunction = LongUnaryOperator.identity();
|
|
||||||
|
|
||||||
public GlBuffer() {
|
public GlBuffer() {
|
||||||
this(GlBufferUsage.STATIC_DRAW);
|
this(GlBufferUsage.STATIC_DRAW);
|
||||||
|
@ -29,63 +21,9 @@ public class GlBuffer extends GlObject {
|
||||||
this.usage = usage;
|
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) {
|
public void upload(MemoryBlock memoryBlock) {
|
||||||
upload(memoryBlock.ptr(), memoryBlock.size());
|
upload(memoryBlock.ptr(), memoryBlock.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void upload(long ptr, long size) {
|
public void upload(long ptr, long size) {
|
||||||
FlwMemoryTracker._freeGPUMemory(this.size);
|
FlwMemoryTracker._freeGPUMemory(this.size);
|
||||||
Buffer.IMPL.data(handle(), size, ptr, usage.glEnum);
|
Buffer.IMPL.data(handle(), size, ptr, usage.glEnum);
|
||||||
|
@ -93,12 +31,12 @@ public class GlBuffer extends GlObject {
|
||||||
FlwMemoryTracker._allocGPUMemory(this.size);
|
FlwMemoryTracker._allocGPUMemory(this.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MappedBuffer map() {
|
public void uploadSpan(long offset, MemoryBlock memoryBlock) {
|
||||||
return new MappedBuffer(handle(), size);
|
uploadSpan(offset, memoryBlock.ptr(), memoryBlock.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void growthFunction(LongUnaryOperator growthFunction) {
|
public void uploadSpan(long offset, long ptr, long size) {
|
||||||
this.growthFunction = growthFunction;
|
Buffer.IMPL.subData(handle(), offset, size, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long size() {
|
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