diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/GlFence.java b/src/main/java/com/jozufozu/flywheel/backend/gl/GlFence.java new file mode 100644 index 000000000..78f6df423 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/GlFence.java @@ -0,0 +1,41 @@ +package com.jozufozu.flywheel.backend.gl; + +import static org.lwjgl.opengl.GL32.GL_ALREADY_SIGNALED; +import static org.lwjgl.opengl.GL32.GL_CONDITION_SATISFIED; +import static org.lwjgl.opengl.GL32.GL_SYNC_FLUSH_COMMANDS_BIT; +import static org.lwjgl.opengl.GL32.GL_SYNC_GPU_COMMANDS_COMPLETE; +import static org.lwjgl.opengl.GL32.GL_UNSIGNALED; +import static org.lwjgl.opengl.GL32.glClientWaitSync; +import static org.lwjgl.opengl.GL32.glDeleteSync; +import static org.lwjgl.opengl.GL32.glFenceSync; + +public class GlFence { + + private long fence; + + public void post() { + clear(); + + fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + } + + public void clear() { + if (fence != 0) { + glDeleteSync(fence); + fence = 0; + } + } + + public void waitSync() { + if (fence != 0) { + int waitReturn = GL_UNSIGNALED; + while (waitReturn != GL_ALREADY_SIGNALED && waitReturn != GL_CONDITION_SATISFIED) { + waitReturn = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 1); + } + + glDeleteSync(fence); + } + + fence = 0; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java index 29fdd16db..54063a15d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java @@ -4,6 +4,7 @@ import java.nio.ByteBuffer; import org.lwjgl.opengl.GL20; +import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GlObject; public abstract class GlBuffer extends GlObject { @@ -15,6 +16,25 @@ public abstract class GlBuffer extends GlObject { this.type = type; } + /** + * Request a Persistent mapped buffer. + * + *
+ * If Persistent buffers are supported, this will provide one. Otherwise it will fall back to a classic mapped + * buffer. + *
+ * + * @param type The type of buffer you want. + * @return A buffer that will be persistent if the driver supports it. + */ + public static GlBuffer requestPersistent(GlBufferType type) { + if (Backend.getInstance().compat.bufferStorageSupported()) { + return new PersistentGlBuffer(type); + } else { + return new MappedGlBuffer(type); + } + } + public GlBufferType getBufferTarget() { return type; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBufferImpl.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedGlBuffer.java similarity index 86% rename from src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBufferImpl.java rename to src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedGlBuffer.java index 7002e5505..e05362a46 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBufferImpl.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedGlBuffer.java @@ -8,15 +8,15 @@ import org.lwjgl.opengl.GL30; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.versioned.MapBufferRange; -public class GlBufferImpl extends GlBuffer { +public class MappedGlBuffer extends GlBuffer { protected final GlBufferUsage usage; - public GlBufferImpl(GlBufferType type) { + public MappedGlBuffer(GlBufferType type) { this(type, GlBufferUsage.STATIC_DRAW); } - public GlBufferImpl(GlBufferType type, GlBufferUsage usage) { + public MappedGlBuffer(GlBufferType type, GlBufferUsage usage) { super(type); this.usage = usage; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java index d58bc8e23..b58a9f43b 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java @@ -4,6 +4,9 @@ import static org.lwjgl.opengl.GL44.*; import java.nio.ByteBuffer; +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.gl.GlFence; + public class PersistentGlBuffer extends GlBuffer { @@ -11,17 +14,18 @@ public class PersistentGlBuffer extends GlBuffer { int flags; long size; - private long fence = -1; + GlFence fence; public PersistentGlBuffer(GlBufferType type) { super(type); flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT; + fence = new GlFence(); } @Override public void doneForThisFrame() { - fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + fence.post(); } @Override @@ -33,7 +37,9 @@ public class PersistentGlBuffer extends GlBuffer { _create(); } - glBufferStorage(type.glEnum, size, flags); + fence.clear(); + + Backend.getInstance().compat.bufferStorage.bufferStorage(type.glEnum, size, flags); buffer = new PersistentMappedBuffer(this); } @@ -46,16 +52,7 @@ public class PersistentGlBuffer extends GlBuffer { @Override public MappedBuffer getBuffer(int offset, int length) { - if (fence != -1) { - int waitReturn = GL_UNSIGNALED; - while (waitReturn != GL_ALREADY_SIGNALED && waitReturn != GL_CONDITION_SATISFIED) { - waitReturn = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 1); - } - - glDeleteSync(fence); - } - - fence = -1; + fence.waitSync(); buffer.position(offset); diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentMappedBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentMappedBuffer.java index 03516f0c8..9d3dbcfdb 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentMappedBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentMappedBuffer.java @@ -6,6 +6,8 @@ import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL44; import org.lwjgl.opengl.GL46; +import com.jozufozu.flywheel.backend.Backend; + public class PersistentMappedBuffer extends MappedBuffer { PersistentGlBuffer owner; @@ -14,7 +16,7 @@ public class PersistentMappedBuffer extends MappedBuffer { super(buffer); owner = buffer; - ByteBuffer byteBuffer = GL44.glMapBufferRange(owner.type.glEnum, 0, owner.size, owner.flags); + ByteBuffer byteBuffer = Backend.getInstance().compat.mapBufferRange.mapBuffer(owner.type, 0, owner.size, owner.flags); setInternal(byteBuffer); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/BufferStorage.java b/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/BufferStorage.java new file mode 100644 index 000000000..53964f078 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/BufferStorage.java @@ -0,0 +1,44 @@ +package com.jozufozu.flywheel.backend.gl.versioned; + +import org.lwjgl.opengl.ARBBufferStorage; +import org.lwjgl.opengl.GL44; +import org.lwjgl.opengl.GLCapabilities; + +public enum BufferStorage implements GlVersioned { + + GL44CORE { + @Override + public boolean supported(GLCapabilities caps) { + return caps.OpenGL44; + } + + @Override + public void bufferStorage(int target, long size, int flags) { + GL44.glBufferStorage(target, size, flags); + } + }, + ARB { + @Override + public boolean supported(GLCapabilities caps) { + return caps.GL_ARB_buffer_storage; + } + + @Override + public void bufferStorage(int target, long size, int flags) { + ARBBufferStorage.glBufferStorage(target, size, flags); + } + }, + UNSUPPORTED { + @Override + public boolean supported(GLCapabilities caps) { + return true; + } + + @Override + public void bufferStorage(int target, long size, int flags) { + throw new UnsupportedOperationException(); + } + }; + + public abstract void bufferStorage(int target, long size, int flags); +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java b/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java index aaebb3625..348fa7d86 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/versioned/GlCompat.java @@ -29,6 +29,7 @@ public class GlCompat { public final DrawInstanced drawInstanced; public final Blit blit; public final Framebuffer fbo; + public final BufferStorage bufferStorage; public final RGPixelFormat pixelFormat; @@ -40,6 +41,7 @@ public class GlCompat { drawInstanced = getLatest(DrawInstanced.class, caps); blit = getLatest(Blit.class, caps); fbo = getLatest(Framebuffer.class, caps); + bufferStorage = getLatest(BufferStorage.class, caps); pixelFormat = getLatest(RGPixelFormat.class, caps); } @@ -64,6 +66,10 @@ public class GlCompat { return blit != Blit.UNSUPPORTED; } + public boolean bufferStorageSupported() { + return bufferStorage != BufferStorage.UNSUPPORTED; + } + /** * Get the most compatible version of a specific OpenGL feature by iterating over enum constants in order. * diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java index 6d72a12da..c85980c52 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java @@ -8,10 +8,8 @@ import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GlVertexArray; import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat; import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; -import com.jozufozu.flywheel.backend.gl.buffer.GlBufferImpl; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer; -import com.jozufozu.flywheel.backend.gl.buffer.PersistentGlBuffer; import com.jozufozu.flywheel.backend.material.MaterialSpec; import com.jozufozu.flywheel.backend.model.IBufferedModel; import com.jozufozu.flywheel.backend.model.IndexedModel; @@ -110,7 +108,7 @@ public class Instancer