From aa38ae41259f2f220daf77e082fa3b12c3501595 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Sun, 7 May 2023 15:38:45 -0700 Subject: [PATCH] Separate separate attributes - Add new GL43 vertex array impl - GlNumericType cleaning - Make GlBuffer growth more abstract - Organize VertexArrayGL3, track bound ebo --- .../flywheel/api/layout/BufferLayout.java | 2 +- .../engine/instancing/GPUInstancer.java | 4 +- .../engine/instancing/InstancedMeshPool.java | 2 +- .../jozufozu/flywheel/gl/GlNumericType.java | 44 ++------- .../flywheel/gl/array/GlVertexArray.java | 2 + .../flywheel/gl/array/GlVertexArrayDSA.java | 8 +- .../flywheel/gl/array/GlVertexArrayGL3.java | 87 +++++++++-------- .../GlVertexArraySeparateAttributes.java | 93 +++++++++++++++++++ .../flywheel/gl/array/VertexAttribute.java | 10 +- .../jozufozu/flywheel/gl/buffer/GlBuffer.java | 16 ++-- .../flywheel/lib/util/QuadConverter.java | 2 +- 11 files changed, 175 insertions(+), 95 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArraySeparateAttributes.java diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/BufferLayout.java b/src/main/java/com/jozufozu/flywheel/api/layout/BufferLayout.java index a873f3719..b289a436a 100644 --- a/src/main/java/com/jozufozu/flywheel/api/layout/BufferLayout.java +++ b/src/main/java/com/jozufozu/flywheel/api/layout/BufferLayout.java @@ -56,7 +56,7 @@ public class BufferLayout { private static int calculateStride(List layoutItems) { int stride = 0; for (var spec : layoutItems) { - stride += spec.getByteWidth(); + stride += spec.byteWidth(); } return stride; } 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 c03390875..599bf2284 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 @@ -41,7 +41,7 @@ public class GPUInstancer extends AbstractInstancer { } vbo = new GlBuffer(GlBufferUsage.DYNAMIC_DRAW); - vbo.growthMargin(instanceStride * 16); + vbo.growthFunction(l -> Math.max(l + (long) instanceStride * 16, (long) (l * 1.6))); } public void update() { @@ -70,7 +70,7 @@ public class GPUInstancer extends AbstractInstancer { 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)); + writer.write(ptr + (long) instanceStride * i, instances.get(i)); } changed.clear(); 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 c2a671b00..5e00a0604 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 @@ -40,7 +40,7 @@ public class InstancedMeshPool { this.vertexType = vertexType; int stride = vertexType.getLayout().getStride(); vbo = new GlBuffer(); - vbo.growthMargin(stride * 32); + vbo.growthFunction(l -> Math.max(l + stride * 32L, (long) (l * 1.6))); } public VertexType getVertexType() { diff --git a/src/main/java/com/jozufozu/flywheel/gl/GlNumericType.java b/src/main/java/com/jozufozu/flywheel/gl/GlNumericType.java index 531063490..19f99c42c 100644 --- a/src/main/java/com/jozufozu/flywheel/gl/GlNumericType.java +++ b/src/main/java/com/jozufozu/flywheel/gl/GlNumericType.java @@ -1,12 +1,5 @@ package com.jozufozu.flywheel.gl; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.Locale; -import java.util.Map; -import java.util.stream.Collectors; - -import org.jetbrains.annotations.Nullable; import org.lwjgl.opengl.GL11; public enum GlNumericType { @@ -20,13 +13,9 @@ public enum GlNumericType { DOUBLE(8, "double", GL11.GL_DOUBLE), ; - private static final GlNumericType[] VALUES = values(); - private static final Map NAME_LOOKUP = Arrays.stream(VALUES) - .collect(Collectors.toMap(GlNumericType::getTypeName, type -> type)); - - private final int byteWidth; - private final String typeName; - private final int glEnum; + public final int byteWidth; + public final String typeName; + public final int glEnum; GlNumericType(int bytes, String name, int glEnum) { this.byteWidth = bytes; @@ -34,31 +23,16 @@ public enum GlNumericType { this.glEnum = glEnum; } - public int getByteWidth() { - return this.byteWidth; + public int byteWidth() { + return byteWidth; } - public String getTypeName() { - return this.typeName; + public String typeName() { + return typeName; } - public int getGlEnum() { - return this.glEnum; - } - - public void castAndBuffer(ByteBuffer buf, int val) { - if (this == UBYTE || this == BYTE) { - buf.put((byte) val); - } else if (this == USHORT || this == SHORT) { - buf.putShort((short) val); - } else if (this == UINT || this == INT) { - buf.putInt(val); - } - } - - @Nullable - public static GlNumericType byName(String name) { - return name == null ? null : NAME_LOOKUP.get(name.toLowerCase(Locale.ROOT)); + public int glEnum() { + return glEnum; } @Override diff --git a/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArray.java b/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArray.java index d8c355538..c45a90cf3 100644 --- a/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArray.java +++ b/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArray.java @@ -15,6 +15,8 @@ public abstract class GlVertexArray extends GlObject { public static GlVertexArray create() { if (GlVertexArrayDSA.SUPPORTED) { return new GlVertexArrayDSA(); + } else if (GlVertexArraySeparateAttributes.SUPPORTED) { + return new GlVertexArraySeparateAttributes(); } else if (GlVertexArrayGL3.Core33.SUPPORTED) { return new GlVertexArrayGL3.Core33(); } else if (GlVertexArrayGL3.ARB.SUPPORTED) { diff --git a/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayDSA.java b/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayDSA.java index b31edc78a..cf3248d6b 100644 --- a/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayDSA.java +++ b/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayDSA.java @@ -57,11 +57,9 @@ public class GlVertexArrayDSA extends GlVertexArray { if (!attribute.equals(attributes[attribIndex])) { if (attribute instanceof VertexAttribute.Float f) { - GL45C.glVertexArrayAttribFormat(handle, attribIndex, f.size(), f.type() - .getGlEnum(), f.normalized(), offset); + GL45C.glVertexArrayAttribFormat(handle, attribIndex, f.size(), f.type().glEnum, f.normalized(), offset); } else if (attribute instanceof VertexAttribute.Int vi) { - GL45C.glVertexArrayAttribIFormat(handle, attribIndex, vi.size(), vi.type() - .getGlEnum(), offset); + GL45C.glVertexArrayAttribIFormat(handle, attribIndex, vi.size(), vi.type().glEnum, offset); } attributes[attribIndex] = attribute; } @@ -72,7 +70,7 @@ public class GlVertexArrayDSA extends GlVertexArray { } attribIndex++; - offset += attribute.getByteWidth(); + offset += attribute.byteWidth(); } } diff --git a/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayGL3.java b/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayGL3.java index 7104f840b..a42d8d905 100644 --- a/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayGL3.java +++ b/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayGL3.java @@ -23,7 +23,8 @@ public abstract class GlVertexArrayGL3 extends GlVertexArray { private final long[] bindingOffsets = new long[MAX_ATTRIB_BINDINGS]; private final int[] bindingStrides = new int[MAX_ATTRIB_BINDINGS]; private final int[] bindingDivisors = new int[MAX_ATTRIB_BINDINGS]; - private int elementBufferBinding = 0; + private int requestedElementBuffer = 0; + private int boundElementBuffer = 0; public GlVertexArrayGL3() { handle(GL30.glGenVertexArrays()); @@ -33,42 +34,11 @@ public abstract class GlVertexArrayGL3 extends GlVertexArray { public void bindForDraw() { super.bindForDraw(); - for (int attribIndex = attributeDirty.nextSetBit(0); attribIndex < MAX_ATTRIB_BINDINGS && attribIndex >= 0; attribIndex = attributeDirty.nextSetBit(attribIndex + 1)) { + maybeUpdateAttributes(); - int bindingIndex = attributeBindings[attribIndex]; - var attribute = attributes[attribIndex]; - - if (bindingIndex == -1 || attribute == null) { - continue; - } - - GlBufferType.ARRAY_BUFFER.bind(bindingBuffers[bindingIndex]); - GL20C.glEnableVertexAttribArray(attribIndex); - - long offset = bindingOffsets[bindingIndex] + attributeOffsets[attribIndex]; - int stride = bindingStrides[bindingIndex]; - - if (attribute instanceof VertexAttribute.Float f) { - GL32.glVertexAttribPointer(attribIndex, f.size(), f.type() - .getGlEnum(), f.normalized(), stride, offset); - } else if (attribute instanceof VertexAttribute.Int vi) { - GL32.glVertexAttribIPointer(attribIndex, vi.size(), vi.type() - .getGlEnum(), stride, offset); - } - - int divisor = bindingDivisors[bindingIndex]; - if (divisor != 0) { - setDivisor(attribIndex, divisor); - } - } - - GlBufferType.ELEMENT_ARRAY_BUFFER.bind(elementBufferBinding); - - attributeDirty.clear(); + maybeUpdateEBOBinding(); } - protected abstract void setDivisor(int attribIndex, int divisor); - @Override public void bindVertexBuffer(int bindingIndex, int vbo, long offset, int stride) { if (bindingBuffers[bindingIndex] != vbo || bindingOffsets[bindingIndex] != offset || bindingStrides[bindingIndex] != stride) { @@ -83,7 +53,6 @@ public abstract class GlVertexArrayGL3 extends GlVertexArray { } } } - @Override public void setBindingDivisor(int bindingIndex, int divisor) { if (bindingDivisors[bindingIndex] != divisor) { @@ -104,15 +73,59 @@ public abstract class GlVertexArrayGL3 extends GlVertexArray { attributeDirty.set(attribIndex); attribIndex++; - offset += attribute.getByteWidth(); + offset += attribute.byteWidth(); } } @Override public void setElementBuffer(int ebo) { - elementBufferBinding = ebo; + requestedElementBuffer = ebo; } + private void maybeUpdateEBOBinding() { + if (requestedElementBuffer != boundElementBuffer) { + GlBufferType.ELEMENT_ARRAY_BUFFER.bind(requestedElementBuffer); + boundElementBuffer = requestedElementBuffer; + } + } + + private void maybeUpdateAttributes() { + for (int attribIndex = attributeDirty.nextSetBit(0); attribIndex < MAX_ATTRIB_BINDINGS && attribIndex >= 0; attribIndex = attributeDirty.nextSetBit(attribIndex + 1)) { + updateAttribute(attribIndex); + } + attributeDirty.clear(); + } + + private void updateAttribute(int attribIndex) { + int bindingIndex = attributeBindings[attribIndex]; + var attribute = attributes[attribIndex]; + + if (bindingIndex == -1 || attribute == null) { + return; + } + + GlBufferType.ARRAY_BUFFER.bind(bindingBuffers[bindingIndex]); + GL20C.glEnableVertexAttribArray(attribIndex); + + long offset = bindingOffsets[bindingIndex] + attributeOffsets[attribIndex]; + int stride = bindingStrides[bindingIndex]; + + if (attribute instanceof VertexAttribute.Float f) { + GL32.glVertexAttribPointer(attribIndex, f.size(), f.type() + .glEnum(), f.normalized(), stride, offset); + } else if (attribute instanceof VertexAttribute.Int vi) { + GL32.glVertexAttribIPointer(attribIndex, vi.size(), vi.type() + .glEnum(), stride, offset); + } + + int divisor = bindingDivisors[bindingIndex]; + if (divisor != 0) { + setDivisor(attribIndex, divisor); + } + } + + protected abstract void setDivisor(int attribIndex, int divisor); + public static class Core33 extends GlVertexArrayGL3 { public static final boolean SUPPORTED = isSupported(); diff --git a/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArraySeparateAttributes.java b/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArraySeparateAttributes.java new file mode 100644 index 000000000..62132c72f --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArraySeparateAttributes.java @@ -0,0 +1,93 @@ +package com.jozufozu.flywheel.gl.array; + +import java.util.BitSet; +import java.util.List; + +import org.lwjgl.opengl.GL43C; +import org.lwjgl.system.Checks; + +import com.jozufozu.flywheel.gl.GlCompat; +import com.jozufozu.flywheel.gl.GlStateTracker; +import com.jozufozu.flywheel.gl.buffer.GlBufferType; +import com.jozufozu.flywheel.util.FlwUtil; + +public class GlVertexArraySeparateAttributes extends GlVertexArray { + public static final boolean SUPPORTED = isSupported(); + private final BitSet attributeEnabled = new BitSet(MAX_ATTRIBS); + private final VertexAttribute[] attributes = new VertexAttribute[MAX_ATTRIBS]; + private final int[] attributeBindings = FlwUtil.initArray(MAX_ATTRIBS, -1); + private final int[] bindingBuffers = new int[MAX_ATTRIB_BINDINGS]; + private final long[] bindingOffsets = new long[MAX_ATTRIB_BINDINGS]; + private final int[] bindingStrides = new int[MAX_ATTRIB_BINDINGS]; + private final int[] bindingDivisors = new int[MAX_ATTRIB_BINDINGS]; + + private int elementBufferBinding = 0; + + public GlVertexArraySeparateAttributes() { + handle(GL43C.glGenVertexArrays()); + } + + @Override + public void bindVertexBuffer(final int bindingIndex, final int vbo, final long offset, final int stride) { + if (bindingBuffers[bindingIndex] != vbo || bindingOffsets[bindingIndex] != offset || bindingStrides[bindingIndex] != stride) { + GlStateTracker.bindVao(handle()); + GL43C.glBindVertexBuffer(bindingIndex, vbo, offset, stride); + bindingBuffers[bindingIndex] = vbo; + bindingOffsets[bindingIndex] = offset; + bindingStrides[bindingIndex] = stride; + } + } + + @Override + public void setBindingDivisor(final int bindingIndex, final int divisor) { + if (bindingDivisors[bindingIndex] != divisor) { + GL43C.glVertexBindingDivisor(bindingIndex, divisor); + bindingDivisors[bindingIndex] = divisor; + } + } + + @Override + public void bindAttributes(final int bindingIndex, final int startAttribIndex, List vertexAttributes) { + GlStateTracker.bindVao(handle()); + int attribIndex = startAttribIndex; + int offset = 0; + + for (var attribute : vertexAttributes) { + if (!attributeEnabled.get(attribIndex)) { + GL43C.glEnableVertexAttribArray(attribIndex); + attributeEnabled.set(attribIndex); + } + + if (!attribute.equals(attributes[attribIndex])) { + if (attribute instanceof VertexAttribute.Float f) { + GL43C.glVertexAttribFormat(attribIndex, f.size(), f.type().glEnum, f.normalized(), offset); + } else if (attribute instanceof VertexAttribute.Int vi) { + GL43C.glVertexAttribIFormat(attribIndex, vi.size(), vi.type().glEnum, offset); + } + attributes[attribIndex] = attribute; + } + + if (attributeBindings[attribIndex] != bindingIndex) { + GL43C.glVertexAttribBinding(attribIndex, bindingIndex); + attributeBindings[attribIndex] = bindingIndex; + } + + attribIndex++; + offset += attribute.byteWidth(); + } + } + + @Override + public void setElementBuffer(int ebo) { + if (elementBufferBinding != ebo) { + GlStateTracker.bindVao(handle()); + GlBufferType.ELEMENT_ARRAY_BUFFER.bind(ebo); + elementBufferBinding = ebo; + } + } + + private static boolean isSupported() { + var c = GlCompat.CAPABILITIES; + return GlCompat.ALLOW_DSA && Checks.checkFunctions(c.glBindVertexBuffer, c.glVertexBindingDivisor, c.glEnableVertexAttribArray, c.glVertexAttribFormat, c.glVertexAttribIFormat, c.glVertexAttribBinding); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/gl/array/VertexAttribute.java b/src/main/java/com/jozufozu/flywheel/gl/array/VertexAttribute.java index 2ecd54a4b..05ddef78e 100644 --- a/src/main/java/com/jozufozu/flywheel/gl/array/VertexAttribute.java +++ b/src/main/java/com/jozufozu/flywheel/gl/array/VertexAttribute.java @@ -3,7 +3,7 @@ package com.jozufozu.flywheel.gl.array; import com.jozufozu.flywheel.gl.GlNumericType; public sealed interface VertexAttribute { - int getByteWidth(); + int byteWidth(); /** * A bindable attribute in a vertex array. @@ -14,8 +14,8 @@ public sealed interface VertexAttribute { */ record Float(GlNumericType type, int size, boolean normalized) implements VertexAttribute { @Override - public int getByteWidth() { - return size * type.getByteWidth(); + public int byteWidth() { + return size * type.byteWidth(); } } @@ -27,8 +27,8 @@ public sealed interface VertexAttribute { */ record Int(GlNumericType type, int size) implements VertexAttribute { @Override - public int getByteWidth() { - return size * type.getByteWidth(); + public int byteWidth() { + return size * type.byteWidth(); } } } 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 393a84326..ed8c4118f 100644 --- a/src/main/java/com/jozufozu/flywheel/gl/buffer/GlBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/gl/buffer/GlBuffer.java @@ -1,7 +1,5 @@ package com.jozufozu.flywheel.gl.buffer; -import static org.lwjgl.opengl.GL15.glDeleteBuffers; - import org.lwjgl.system.MemoryUtil; import com.jozufozu.flywheel.gl.GlObject; @@ -9,6 +7,8 @@ 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 { public static final Buffer IMPL = new Buffer.DSA().fallback(); protected final GlBufferUsage usage; @@ -17,9 +17,9 @@ public class GlBuffer extends GlObject { */ protected long size; /** - * How much extra room to give the buffer when we reallocate. + * A mapping to adjust the size of the buffer when allocating. */ - protected int growthMargin; + protected LongUnaryOperator growthFunction = LongUnaryOperator.identity(); public GlBuffer() { this(GlBufferUsage.STATIC_DRAW); @@ -70,7 +70,7 @@ public class GlBuffer extends GlObject { int newHandle = IMPL.create(); IMPL.data(newHandle, size, MemoryUtil.NULL, usage.glEnum); IMPL.copyData(oldHandle, newHandle, 0, 0, oldSize); - glDeleteBuffers(oldHandle); + GlStateManager._glDeleteBuffers(oldHandle); handle(newHandle); FlwMemoryTracker._allocGPUMemory(size); @@ -80,7 +80,7 @@ public class GlBuffer extends GlObject { * Increase the size of the buffer to at least the given capacity. */ private void increaseSize(long capacity) { - size = capacity + growthMargin; + size = growthFunction.apply(capacity); } public void upload(MemoryBlock directBuffer) { @@ -94,8 +94,8 @@ public class GlBuffer extends GlObject { return new MappedBuffer(handle(), size); } - public void growthMargin(int growthMargin) { - this.growthMargin = growthMargin; + public void growthFunction(LongUnaryOperator growthFunction) { + this.growthFunction = growthFunction; } public long size() { diff --git a/src/main/java/com/jozufozu/flywheel/lib/util/QuadConverter.java b/src/main/java/com/jozufozu/flywheel/lib/util/QuadConverter.java index 8c6dfae49..0d01923c1 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/util/QuadConverter.java +++ b/src/main/java/com/jozufozu/flywheel/lib/util/QuadConverter.java @@ -58,7 +58,7 @@ public class QuadConverter { } private void grow(int quads) { - int byteSize = quads * 6 * GlNumericType.UINT.getByteWidth(); + int byteSize = quads * 6 * GlNumericType.UINT.byteWidth(); final long ptr = MemoryUtil.nmemAlloc(byteSize); fillBuffer(ptr, quads);