mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-06 04:16:36 +01:00
Separate separate attributes
- Add new GL43 vertex array impl - GlNumericType cleaning - Make GlBuffer growth more abstract - Organize VertexArrayGL3, track bound ebo
This commit is contained in:
parent
e2bcc5f325
commit
aa38ae4125
11 changed files with 175 additions and 95 deletions
|
@ -56,7 +56,7 @@ public class BufferLayout {
|
|||
private static int calculateStride(List<VertexAttribute> layoutItems) {
|
||||
int stride = 0;
|
||||
for (var spec : layoutItems) {
|
||||
stride += spec.getByteWidth();
|
||||
stride += spec.byteWidth();
|
||||
}
|
||||
return stride;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ public class GPUInstancer<I extends Instance> extends AbstractInstancer<I> {
|
|||
}
|
||||
|
||||
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<I extends Instance> extends AbstractInstancer<I> {
|
|||
|
||||
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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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<String, GlNumericType> 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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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<VertexAttribute> 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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue