mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-11-10 12:34:11 +01:00
Buffing the old works
- GlBuffer no longer has an explicit bind method or binding target - Use READ/WRITE BUFFER for all data operations - Make MappedBuffer simpler and more RAII - Remove dead methods from GlBuffer - Don't actually need to clear the tail of GPUInstancers on shrink - Implement actual capability check for indirect (I think I check all the extensions)
This commit is contained in:
parent
ef7c259f43
commit
f1f289124d
@ -9,7 +9,6 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.api.event.ReloadRenderersEvent;
|
||||
import com.jozufozu.flywheel.api.uniform.ShaderUniforms;
|
||||
import com.jozufozu.flywheel.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.lib.math.MoreMath;
|
||||
import com.jozufozu.flywheel.lib.math.RenderMath;
|
||||
@ -35,7 +34,7 @@ public class UniformBuffer {
|
||||
private final GlBuffer buffer;
|
||||
|
||||
private UniformBuffer() {
|
||||
buffer = new GlBuffer(GlBufferType.UNIFORM_BUFFER);
|
||||
buffer = new GlBuffer();
|
||||
providerSet = new ProviderSet(ShaderUniforms.REGISTRY.getAll());
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ import com.jozufozu.flywheel.api.layout.BufferLayout;
|
||||
import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
|
||||
import com.jozufozu.flywheel.gl.array.GlVertexArray;
|
||||
import com.jozufozu.flywheel.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.gl.buffer.GlBufferUsage;
|
||||
import com.jozufozu.flywheel.gl.buffer.MappedBuffer;
|
||||
|
||||
@ -41,7 +40,7 @@ public class GPUInstancer<I extends Instance> extends AbstractInstancer<I> {
|
||||
return;
|
||||
}
|
||||
|
||||
vbo = new GlBuffer(GlBufferType.ARRAY_BUFFER, GlBufferUsage.DYNAMIC_DRAW);
|
||||
vbo = new GlBuffer(GlBufferUsage.DYNAMIC_DRAW);
|
||||
vbo.setGrowthMargin(instanceStride * 16);
|
||||
}
|
||||
|
||||
@ -65,16 +64,11 @@ public class GPUInstancer<I extends Instance> extends AbstractInstancer<I> {
|
||||
return;
|
||||
}
|
||||
|
||||
int count = instances.size();
|
||||
long clearStart = instanceStride * (long) count;
|
||||
long clearLength = vbo.getSize() - clearStart;
|
||||
|
||||
try (MappedBuffer buf = vbo.map()) {
|
||||
buf.clear(clearStart, clearLength);
|
||||
|
||||
long ptr = buf.getPtr();
|
||||
long ptr = buf.ptr();
|
||||
InstanceWriter<I> writer = type.getWriter();
|
||||
|
||||
int count = instances.size();
|
||||
for (int i = changed.nextSetBit(0); i >= 0 && i < count; i = changed.nextSetBit(i + 1)) {
|
||||
writer.write(ptr + instanceStride * i, instances.get(i));
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ import com.jozufozu.flywheel.gl.GlPrimitive;
|
||||
import com.jozufozu.flywheel.gl.array.GlVertexArray;
|
||||
import com.jozufozu.flywheel.gl.buffer.ElementBuffer;
|
||||
import com.jozufozu.flywheel.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.gl.buffer.MappedBuffer;
|
||||
|
||||
public class InstancedMeshPool {
|
||||
@ -39,7 +38,7 @@ public class InstancedMeshPool {
|
||||
public InstancedMeshPool(VertexType vertexType) {
|
||||
this.vertexType = vertexType;
|
||||
int stride = vertexType.getLayout().getStride();
|
||||
vbo = new GlBuffer(GlBufferType.ARRAY_BUFFER);
|
||||
vbo = new GlBuffer();
|
||||
vbo.setGrowthMargin(stride * 32);
|
||||
}
|
||||
|
||||
@ -75,20 +74,20 @@ public class InstancedMeshPool {
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
if (dirty) {
|
||||
if (anyToRemove) {
|
||||
processDeletions();
|
||||
}
|
||||
|
||||
if (realloc()) {
|
||||
uploadAll();
|
||||
} else {
|
||||
uploadPending();
|
||||
}
|
||||
|
||||
dirty = false;
|
||||
pendingUpload.clear();
|
||||
if (!dirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (anyToRemove) {
|
||||
processDeletions();
|
||||
}
|
||||
|
||||
vbo.ensureCapacity(byteSize);
|
||||
|
||||
uploadPending();
|
||||
|
||||
dirty = false;
|
||||
pendingUpload.clear();
|
||||
}
|
||||
|
||||
private void processDeletions() {
|
||||
@ -117,35 +116,9 @@ public class InstancedMeshPool {
|
||||
this.anyToRemove = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assumes vbo is bound.
|
||||
*
|
||||
* @return true if the buffer was reallocated
|
||||
*/
|
||||
private boolean realloc() {
|
||||
return vbo.ensureCapacity(byteSize);
|
||||
}
|
||||
|
||||
private void uploadAll() {
|
||||
try (MappedBuffer mapped = vbo.map()) {
|
||||
long ptr = mapped.getPtr();
|
||||
|
||||
int byteIndex = 0;
|
||||
for (BufferedMesh mesh : allBuffered) {
|
||||
mesh.byteIndex = byteIndex;
|
||||
|
||||
mesh.buffer(ptr);
|
||||
|
||||
byteIndex += mesh.size();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Flywheel.LOGGER.error("Error uploading pooled meshes:", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void uploadPending() {
|
||||
try (MappedBuffer mapped = vbo.map()) {
|
||||
long ptr = mapped.getPtr();
|
||||
long ptr = mapped.ptr();
|
||||
|
||||
for (BufferedMesh mesh : pendingUpload) {
|
||||
mesh.buffer(ptr);
|
||||
|
@ -4,21 +4,13 @@ import static org.lwjgl.opengl.GL15.glBufferData;
|
||||
import static org.lwjgl.opengl.GL15.glDeleteBuffers;
|
||||
import static org.lwjgl.opengl.GL15.glGenBuffers;
|
||||
import static org.lwjgl.opengl.GL15.nglBufferData;
|
||||
import static org.lwjgl.opengl.GL30.GL_MAP_WRITE_BIT;
|
||||
import static org.lwjgl.opengl.GL30.nglMapBufferRange;
|
||||
import static org.lwjgl.opengl.GL31.glCopyBufferSubData;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.gl.GlObject;
|
||||
import com.jozufozu.flywheel.gl.error.GlError;
|
||||
import com.jozufozu.flywheel.gl.error.GlException;
|
||||
import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker;
|
||||
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||
|
||||
public class GlBuffer extends GlObject {
|
||||
|
||||
public final GlBufferType type;
|
||||
protected final GlBufferUsage usage;
|
||||
/**
|
||||
* The size (in bytes) of the buffer on the GPU.
|
||||
@ -29,16 +21,18 @@ public class GlBuffer extends GlObject {
|
||||
*/
|
||||
protected int growthMargin;
|
||||
|
||||
public GlBuffer(GlBufferType type) {
|
||||
this(type, GlBufferUsage.STATIC_DRAW);
|
||||
public GlBuffer() {
|
||||
this(GlBufferUsage.STATIC_DRAW);
|
||||
}
|
||||
|
||||
public GlBuffer(GlBufferType type, GlBufferUsage usage) {
|
||||
public GlBuffer(GlBufferUsage usage) {
|
||||
setHandle(glGenBuffers());
|
||||
this.type = type;
|
||||
this.usage = usage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the buffer was recreated.
|
||||
*/
|
||||
public boolean ensureCapacity(long size) {
|
||||
if (size < 0) {
|
||||
throw new IllegalArgumentException("Size " + size + " < 0");
|
||||
@ -50,8 +44,8 @@ public class GlBuffer extends GlObject {
|
||||
|
||||
if (this.size == 0) {
|
||||
this.size = size;
|
||||
bind();
|
||||
glBufferData(type.glEnum, size, usage.glEnum);
|
||||
GlBufferType.COPY_WRITE_BUFFER.bind(handle());
|
||||
glBufferData(GlBufferType.COPY_WRITE_BUFFER.glEnum, size, usage.glEnum);
|
||||
FlwMemoryTracker._allocGPUMemory(size);
|
||||
|
||||
return true;
|
||||
@ -76,36 +70,25 @@ public class GlBuffer extends GlObject {
|
||||
var newHandle = glGenBuffers();
|
||||
|
||||
GlBufferType.COPY_READ_BUFFER.bind(oldHandle);
|
||||
type.bind(newHandle);
|
||||
GlBufferType.COPY_WRITE_BUFFER.bind(newHandle);
|
||||
|
||||
glBufferData(type.glEnum, newSize, usage.glEnum);
|
||||
glCopyBufferSubData(GlBufferType.COPY_READ_BUFFER.glEnum, type.glEnum, 0, 0, oldSize);
|
||||
glBufferData(GlBufferType.COPY_WRITE_BUFFER.glEnum, newSize, usage.glEnum);
|
||||
glCopyBufferSubData(GlBufferType.COPY_READ_BUFFER.glEnum, GlBufferType.COPY_WRITE_BUFFER.glEnum, 0, 0, oldSize);
|
||||
|
||||
glDeleteBuffers(oldHandle);
|
||||
setHandle(newHandle);
|
||||
}
|
||||
|
||||
public void upload(MemoryBlock directBuffer) {
|
||||
bind();
|
||||
FlwMemoryTracker._freeGPUMemory(size);
|
||||
nglBufferData(type.glEnum, directBuffer.size(), directBuffer.ptr(), usage.glEnum);
|
||||
GlBufferType.COPY_WRITE_BUFFER.bind(handle());
|
||||
nglBufferData(GlBufferType.COPY_WRITE_BUFFER.glEnum, directBuffer.size(), directBuffer.ptr(), usage.glEnum);
|
||||
this.size = directBuffer.size();
|
||||
FlwMemoryTracker._allocGPUMemory(size);
|
||||
}
|
||||
|
||||
public MappedBuffer map() {
|
||||
bind();
|
||||
long ptr = nglMapBufferRange(type.glEnum, 0, size, GL_MAP_WRITE_BIT);
|
||||
|
||||
if (ptr == MemoryUtil.NULL) {
|
||||
throw new GlException(GlError.poll(), "Could not map buffer");
|
||||
}
|
||||
|
||||
return new MappedBuffer(this, ptr, 0, size);
|
||||
}
|
||||
|
||||
public boolean isPersistent() {
|
||||
return false;
|
||||
return new MappedBuffer(handle(), size);
|
||||
}
|
||||
|
||||
public void setGrowthMargin(int growthMargin) {
|
||||
@ -116,18 +99,6 @@ public class GlBuffer extends GlObject {
|
||||
return size;
|
||||
}
|
||||
|
||||
public GlBufferType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
type.bind(handle());
|
||||
}
|
||||
|
||||
public void unbind() {
|
||||
type.unbind();
|
||||
}
|
||||
|
||||
protected void deleteInternal(int handle) {
|
||||
glDeleteBuffers(handle);
|
||||
FlwMemoryTracker._freeGPUMemory(size);
|
||||
|
@ -1,59 +1,42 @@
|
||||
package com.jozufozu.flywheel.gl.buffer;
|
||||
|
||||
import static org.lwjgl.opengl.GL30.GL_MAP_WRITE_BIT;
|
||||
import static org.lwjgl.opengl.GL30.nglMapBufferRange;
|
||||
import static org.lwjgl.system.MemoryUtil.NULL;
|
||||
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
public class MappedBuffer implements AutoCloseable {
|
||||
import com.jozufozu.flywheel.gl.error.GlError;
|
||||
import com.jozufozu.flywheel.gl.error.GlException;
|
||||
|
||||
private final long offset;
|
||||
private final long length;
|
||||
private final GlBuffer owner;
|
||||
private final boolean persistent;
|
||||
public class MappedBuffer implements AutoCloseable {
|
||||
private final int glBuffer;
|
||||
private long ptr;
|
||||
|
||||
public MappedBuffer(GlBuffer owner, long ptr, long offset, long length) {
|
||||
this.ptr = ptr;
|
||||
this.owner = owner;
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
persistent = owner.isPersistent();
|
||||
public MappedBuffer(int glBuffer, long size) {
|
||||
this.glBuffer = glBuffer;
|
||||
|
||||
GlBufferType.COPY_READ_BUFFER.bind(glBuffer);
|
||||
ptr = nglMapBufferRange(GlBufferType.COPY_READ_BUFFER.glEnum, 0, size, GL_MAP_WRITE_BIT);
|
||||
|
||||
if (ptr == MemoryUtil.NULL) {
|
||||
throw new GlException(GlError.poll(), "Could not map buffer");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the changes in client memory available to the GPU.
|
||||
*/
|
||||
public void flush() {
|
||||
if (persistent) return;
|
||||
|
||||
if (ptr == NULL) return;
|
||||
|
||||
owner.bind();
|
||||
GL15.glUnmapBuffer(owner.getType().glEnum);
|
||||
ptr = NULL;
|
||||
public long ptr() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
flush();
|
||||
}
|
||||
|
||||
public long getPtr() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
public void clear(long clearStart, long clearLength) {
|
||||
if (clearLength <= 0) {
|
||||
if (ptr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clearStart < offset || clearStart + clearLength > offset + length) {
|
||||
throw new IndexOutOfBoundsException("Clear range [" + clearStart + "," + (clearStart + clearLength) + "] is not mapped");
|
||||
}
|
||||
|
||||
long addr = ptr + clearStart;
|
||||
|
||||
MemoryUtil.memSet(addr, 0, clearLength);
|
||||
GlBufferType.COPY_READ_BUFFER.bind(glBuffer);
|
||||
GL15.glUnmapBuffer(GlBufferType.COPY_READ_BUFFER.glEnum);
|
||||
ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.jozufozu.flywheel.gl.versioned;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.lwjgl.PointerBuffer;
|
||||
import org.lwjgl.opengl.GL;
|
||||
@ -18,17 +18,18 @@ import net.minecraft.Util;
|
||||
* system.
|
||||
*/
|
||||
public class GlCompat {
|
||||
private static final GLCapabilities caps;
|
||||
public static final VertexArray vertexArray;
|
||||
public static final BufferStorage bufferStorage;
|
||||
public static final boolean amd;
|
||||
public static final boolean supportsIndirect;
|
||||
|
||||
static {
|
||||
GLCapabilities caps = GL.createCapabilities();
|
||||
bufferStorage = getLatest(BufferStorage.class, caps);
|
||||
vertexArray = getLatest(VertexArray.class, caps);
|
||||
supportsIndirect = caps.OpenGL46;
|
||||
amd = _isAmdWindows();
|
||||
caps = GL.createCapabilities();
|
||||
bufferStorage = getLatest(BufferStorage.class);
|
||||
vertexArray = getLatest(VertexArray.class);
|
||||
supportsIndirect = _decideIfWeSupportIndirect();
|
||||
amd = _decideIfWeAreAMDWindows();
|
||||
}
|
||||
|
||||
private GlCompat() {
|
||||
@ -46,29 +47,30 @@ public class GlCompat {
|
||||
return supportsIndirect;
|
||||
}
|
||||
|
||||
public static boolean bufferStorageSupported() {
|
||||
return bufferStorage != BufferStorage.UNSUPPORTED;
|
||||
private static boolean _decideIfWeSupportIndirect() {
|
||||
return caps.OpenGL46 || (
|
||||
caps.GL_ARB_compute_shader &&
|
||||
caps.GL_ARB_shader_draw_parameters &&
|
||||
caps.GL_ARB_base_instance &&
|
||||
caps.GL_ARB_multi_draw_indirect &&
|
||||
caps.GL_ARB_direct_state_access);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the most compatible version of a specific OpenGL feature by iterating over enum constants in order.
|
||||
*
|
||||
* @param clazz The class of the versioning enum.
|
||||
* @param caps The current system's supported features.
|
||||
* @param <V> The type of the versioning enum.
|
||||
* @param clazz The class of the versioning enum.
|
||||
* @return The first defined enum variant to return true.
|
||||
*/
|
||||
private static <V extends Enum<V> & GlVersioned> V getLatest(Class<V> clazz, GLCapabilities caps) {
|
||||
V[] constants = clazz.getEnumConstants();
|
||||
V last = constants[constants.length - 1];
|
||||
if (!last.supported(caps)) {
|
||||
throw new IllegalStateException("");
|
||||
private static <V extends Enum<V> & GlVersioned> V getLatest(Class<V> clazz) {
|
||||
for (V it : clazz.getEnumConstants()) {
|
||||
if (it.supported(GlCompat.caps)) {
|
||||
return Optional.of(it)
|
||||
.get();
|
||||
}
|
||||
}
|
||||
|
||||
return Arrays.stream(constants)
|
||||
.filter(it -> it.supported(caps))
|
||||
.findFirst()
|
||||
.get();
|
||||
throw new IllegalStateException("Invalid versioned enum, must provide at least one supported constant");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -92,7 +94,7 @@ public class GlCompat {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean _isAmdWindows() {
|
||||
private static boolean _decideIfWeAreAMDWindows() {
|
||||
if (Util.getPlatform() != Util.OS.WINDOWS) {
|
||||
return false;
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import com.jozufozu.flywheel.api.layout.BufferLayout;
|
||||
import com.jozufozu.flywheel.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.gl.array.GlVertexArray;
|
||||
import com.jozufozu.flywheel.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.gl.buffer.MappedBuffer;
|
||||
import com.jozufozu.flywheel.lib.layout.CommonItems;
|
||||
import com.jozufozu.flywheel.util.Lazy;
|
||||
@ -35,10 +34,10 @@ public class FullscreenQuad {
|
||||
|
||||
private FullscreenQuad() {
|
||||
try (var restoreState = GlStateTracker.getRestoreState()) {
|
||||
vbo = new GlBuffer(GlBufferType.ARRAY_BUFFER);
|
||||
vbo = new GlBuffer();
|
||||
vbo.ensureCapacity(bufferSize);
|
||||
try (MappedBuffer buffer = vbo.map()) {
|
||||
var ptr = buffer.getPtr();
|
||||
var ptr = buffer.ptr();
|
||||
|
||||
for (var i = 0; i < vertices.length; i++) {
|
||||
MemoryUtil.memPutFloat(ptr + i * Float.BYTES, vertices[i]);
|
||||
|
Loading…
Reference in New Issue
Block a user