diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/UniformBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/engine/UniformBuffer.java index 0d1c7ea6b..cd8b93f0a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/UniformBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/UniformBuffer.java @@ -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()); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/GPUInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/GPUInstancer.java index 32f3358d3..985d11a54 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/GPUInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/GPUInstancer.java @@ -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 extends AbstractInstancer { 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 extends AbstractInstancer { 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 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)); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedMeshPool.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedMeshPool.java index 39d540f23..f52d87fe2 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedMeshPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedMeshPool.java @@ -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); diff --git a/src/main/java/com/jozufozu/flywheel/gl/buffer/GlBuffer.java b/src/main/java/com/jozufozu/flywheel/gl/buffer/GlBuffer.java index 29580bfd8..4724e961d 100644 --- a/src/main/java/com/jozufozu/flywheel/gl/buffer/GlBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/gl/buffer/GlBuffer.java @@ -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); diff --git a/src/main/java/com/jozufozu/flywheel/gl/buffer/MappedBuffer.java b/src/main/java/com/jozufozu/flywheel/gl/buffer/MappedBuffer.java index 62f88ccd3..4803d0fc8 100644 --- a/src/main/java/com/jozufozu/flywheel/gl/buffer/MappedBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/gl/buffer/MappedBuffer.java @@ -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; } } diff --git a/src/main/java/com/jozufozu/flywheel/gl/versioned/GlCompat.java b/src/main/java/com/jozufozu/flywheel/gl/versioned/GlCompat.java index c3ccc796a..bbed659ee 100644 --- a/src/main/java/com/jozufozu/flywheel/gl/versioned/GlCompat.java +++ b/src/main/java/com/jozufozu/flywheel/gl/versioned/GlCompat.java @@ -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 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 & GlVersioned> V getLatest(Class clazz, GLCapabilities caps) { - V[] constants = clazz.getEnumConstants(); - V last = constants[constants.length - 1]; - if (!last.supported(caps)) { - throw new IllegalStateException(""); + private static & GlVersioned> V getLatest(Class 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; } diff --git a/src/main/java/com/jozufozu/flywheel/lib/util/FullscreenQuad.java b/src/main/java/com/jozufozu/flywheel/lib/util/FullscreenQuad.java index 2fc1cd480..3be265223 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/util/FullscreenQuad.java +++ b/src/main/java/com/jozufozu/flywheel/lib/util/FullscreenQuad.java @@ -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]);