Choose between 2 different implementations of a mapped buffer

- MappedBufferRange (GL30) and MappedFullBuffer (GL15) so far
 - Persistent mapping (optionally?) would be nice
This commit is contained in:
JozsefA 2021-05-14 22:51:14 -07:00
parent 8efe8ed01e
commit 79977aee14
26 changed files with 223 additions and 178 deletions

View file

@ -3,10 +3,10 @@ package com.jozufozu.flywheel.backend;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import com.jozufozu.flywheel.backend.gl.GlBuffer;
import com.jozufozu.flywheel.backend.gl.GlBufferType;
import com.jozufozu.flywheel.backend.gl.MappedBufferRange;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.simibubi.create.foundation.render.TemplateBuffer;
import net.minecraft.client.renderer.BufferBuilder;
@ -38,14 +38,14 @@ public abstract class BufferedModel extends TemplateBuffer {
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, invariantSize, GL15.GL_STATIC_DRAW);
// mirror it in system memory so we can write to it
MappedBufferRange buffer = modelVBO.getBuffer(0, invariantSize);
MappedBuffer buffer = modelVBO.getBuffer(0, invariantSize);
for (int i = 0; i < vertexCount; i++) {
copyVertex(buffer, i);
}
buffer.unmap();
buffer.flush();
}
protected abstract void copyVertex(MappedBufferRange to, int index);
protected abstract void copyVertex(MappedBuffer to, int index);
protected abstract VertexFormat getModelFormat();

View file

@ -1,6 +1,6 @@
package com.jozufozu.flywheel.backend.core.materials;
import com.jozufozu.flywheel.backend.gl.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.backend.instancing.InstanceData;
import com.jozufozu.flywheel.backend.instancing.InstancedModel;

View file

@ -1,6 +1,6 @@
package com.jozufozu.flywheel.backend.core.materials;
import com.jozufozu.flywheel.backend.gl.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.backend.instancing.InstancedModel;
import com.jozufozu.flywheel.util.RenderUtil;
import com.mojang.blaze3d.matrix.MatrixStack;

View file

@ -1,6 +1,6 @@
package com.jozufozu.flywheel.backend.core.materials;
import com.jozufozu.flywheel.backend.gl.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.backend.instancing.InstancedModel;
import net.minecraft.util.math.BlockPos;

View file

@ -1,31 +0,0 @@
package com.jozufozu.flywheel.backend.gl;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.GL30;
public class MappedBufferRange extends MappedBuffer {
GlBuffer owner;
public MappedBufferRange(GlBuffer buffer, ByteBuffer internal) {
super(internal);
this.owner = buffer;
}
public static MappedBufferRange create(GlBuffer buffer, long offset, long length, int access) {
ByteBuffer byteBuffer = GL30.glMapBufferRange(buffer.type.glEnum, offset, length, access);
return new MappedBufferRange(buffer, byteBuffer);
}
public MappedBuffer unmap() {
GL30.glUnmapBuffer(owner.type.glEnum);
return this;
}
@Override
public void close() throws Exception {
unmap();
}
}

View file

@ -1,9 +1,13 @@
package com.jozufozu.flywheel.backend.gl;
package com.jozufozu.flywheel.backend.gl.buffer;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlObject;
import com.jozufozu.flywheel.backend.gl.versioned.MapBufferRange;
public class GlBuffer extends GlObject {
protected final GlBufferType type;
@ -43,8 +47,14 @@ public class GlBuffer extends GlObject {
GL15.glBufferData(type.glEnum, size, usage.glEnum);
}
public MappedBufferRange getBuffer(int offset, int length) {
return MappedBufferRange.create(this, offset, length, GL30.GL_MAP_WRITE_BIT);
public MappedBuffer getBuffer(int offset, int length) {
if (Backend.compat.mapBufferRange == MapBufferRange.UNSUPPORTED) {
return new MappedBufferRange(this, offset, length, GL30.GL_MAP_WRITE_BIT);
} else {
MappedFullBuffer fullBuffer = new MappedFullBuffer(this, MappedBufferUsage.WRITE_ONLY);
fullBuffer.position(offset);
return fullBuffer;
}
}
protected void deleteInternal(int handle) {

View file

@ -1,4 +1,4 @@
package com.jozufozu.flywheel.backend.gl;
package com.jozufozu.flywheel.backend.gl.buffer;
import org.lwjgl.opengl.GL15C;
import org.lwjgl.opengl.GL21;

View file

@ -1,4 +1,4 @@
package com.jozufozu.flywheel.backend.gl;
package com.jozufozu.flywheel.backend.gl.buffer;
import org.lwjgl.opengl.GL15;

View file

@ -1,16 +1,40 @@
package com.jozufozu.flywheel.backend.gl;
package com.jozufozu.flywheel.backend.gl.buffer;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.GL15;
public abstract class MappedBuffer implements AutoCloseable {
private final ByteBuffer internal;
protected boolean mapped;
protected final GlBuffer owner;
protected ByteBuffer internal;
public MappedBuffer(ByteBuffer internal) {
public MappedBuffer(GlBuffer owner) {
this.owner = owner;
}
public void setInternal(ByteBuffer internal) {
this.internal = internal;
}
protected abstract void checkAndMap();
public void flush() {
if (mapped) {
GL15.glUnmapBuffer(owner.type.glEnum);
mapped = false;
setInternal(null);
}
}
@Override
public void close() throws Exception {
flush();
}
public MappedBuffer putFloatArray(float[] floats) {
checkAndMap();
internal.asFloatBuffer().put(floats);
internal.position(internal.position() + floats.length * 4);
@ -18,32 +42,44 @@ public abstract class MappedBuffer implements AutoCloseable {
}
public MappedBuffer putByteArray(byte[] bytes) {
checkAndMap();
internal.put(bytes);
return this;
}
/**
* Position this buffer relative to the 0-index in GPU memory.
*
* @param p
* @return This buffer.
*/
public MappedBuffer position(int p) {
checkAndMap();
internal.position(p);
return this;
}
public MappedBuffer putFloat(float f) {
checkAndMap();
internal.putFloat(f);
return this;
}
public MappedBuffer putInt(int i) {
checkAndMap();
internal.putInt(i);
return this;
}
public MappedBuffer put(byte b) {
checkAndMap();
internal.put(b);
return this;
}
public MappedBuffer putVec4(float x, float y, float z, float w) {
checkAndMap();
internal.putFloat(x);
internal.putFloat(y);
internal.putFloat(z);
@ -53,6 +89,7 @@ public abstract class MappedBuffer implements AutoCloseable {
}
public MappedBuffer putVec3(float x, float y, float z) {
checkAndMap();
internal.putFloat(x);
internal.putFloat(y);
internal.putFloat(z);
@ -61,6 +98,7 @@ public abstract class MappedBuffer implements AutoCloseable {
}
public MappedBuffer putVec2(float x, float y) {
checkAndMap();
internal.putFloat(x);
internal.putFloat(y);
@ -68,6 +106,7 @@ public abstract class MappedBuffer implements AutoCloseable {
}
public MappedBuffer putVec3(byte x, byte y, byte z) {
checkAndMap();
internal.put(x);
internal.put(y);
internal.put(z);
@ -76,6 +115,7 @@ public abstract class MappedBuffer implements AutoCloseable {
}
public MappedBuffer putVec2(byte x, byte y) {
checkAndMap();
internal.put(x);
internal.put(y);

View file

@ -0,0 +1,33 @@
package com.jozufozu.flywheel.backend.gl.buffer;
import com.jozufozu.flywheel.backend.Backend;
public class MappedBufferRange extends MappedBuffer {
long offset, length;
int access;
public MappedBufferRange(GlBuffer buffer, long offset, long length, int access) {
super(buffer);
this.offset = offset;
this.length = length;
this.access = access;
}
@Override
public MappedBuffer position(int p) {
if (p < offset || p >= offset + length) {
throw new IndexOutOfBoundsException("Index " + p + " is not mapped");
}
return super.position(p - (int) offset);
}
@Override
protected void checkAndMap() {
if (!mapped) {
setInternal(Backend.compat.mapBufferRange.mapBuffer(owner.type, offset, length, access));
mapped = true;
}
}
}

View file

@ -0,0 +1,16 @@
package com.jozufozu.flywheel.backend.gl.buffer;
import org.lwjgl.opengl.GL15C;
public enum MappedBufferUsage {
READ_ONLY(GL15C.GL_READ_ONLY),
WRITE_ONLY(GL15C.GL_WRITE_ONLY),
READ_WRITE(GL15C.GL_READ_WRITE),
;
int glEnum;
MappedBufferUsage(int glEnum) {
this.glEnum = glEnum;
}
}

View file

@ -0,0 +1,21 @@
package com.jozufozu.flywheel.backend.gl.buffer;
import org.lwjgl.opengl.GL15;
public class MappedFullBuffer extends MappedBuffer {
MappedBufferUsage usage;
public MappedFullBuffer(GlBuffer buffer, MappedBufferUsage usage) {
super(buffer);
this.usage = usage;
}
@Override
protected void checkAndMap() {
if (!mapped) {
setInternal(GL15.glMapBuffer(owner.type.glEnum, usage.glEnum));
mapped = true;
}
}
}

View file

@ -23,7 +23,7 @@ import com.jozufozu.flywheel.backend.gl.versioned.instancing.VertexArrayObject;
* most appropriate version of a feature for the current system.
*/
public class GlCompat {
public final MapBuffer mapBuffer;
public final MapBufferRange mapBufferRange;
public final VertexArrayObject vao;
public final InstancedArrays instancedArrays;
@ -34,7 +34,7 @@ public class GlCompat {
public final RGPixelFormat pixelFormat;
public GlCompat(GLCapabilities caps) {
mapBuffer = getLatest(MapBuffer.class, caps);
mapBufferRange = getLatest(MapBufferRange.class, caps);
vao = getLatest(VertexArrayObject.class, caps);
instancedArrays = getLatest(InstancedArrays.class, caps);

View file

@ -1,94 +0,0 @@
package com.jozufozu.flywheel.backend.gl.versioned;
import java.nio.ByteBuffer;
import java.util.function.Consumer;
import org.lwjgl.opengl.ARBMapBufferRange;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GLCapabilities;
import com.jozufozu.flywheel.backend.gl.GlBufferType;
public enum MapBuffer implements GlVersioned {
GL30_RANGE {
@Override
public boolean supported(GLCapabilities caps) {
return caps.OpenGL30;
}
public ByteBuffer mapBuffer(GlBufferType target, long offset, long length, int access) {
return GL30.glMapBufferRange(target.glEnum, offset, length, access);
}
@Override
public void mapBuffer(GlBufferType target, int offset, int length, Consumer<ByteBuffer> upload) {
ByteBuffer buffer = mapBuffer(target, offset, length, GL30.GL_MAP_WRITE_BIT);
upload.accept(buffer);
buffer.rewind();
GL30.glUnmapBuffer(target.glEnum);
}
},
ARB_RANGE {
@Override
public boolean supported(GLCapabilities caps) {
return caps.GL_ARB_map_buffer_range;
}
public ByteBuffer mapBuffer(GlBufferType target, long offset, long length, int access) {
return ARBMapBufferRange.glMapBufferRange(target.glEnum, offset, length, access);
}
@Override
public void mapBuffer(GlBufferType target, int offset, int length, Consumer<ByteBuffer> upload) {
ByteBuffer buffer = ARBMapBufferRange.glMapBufferRange(target.glEnum, offset, length, GL30.GL_MAP_WRITE_BIT);
upload.accept(buffer);
buffer.rewind();
GL30.glUnmapBuffer(target.glEnum);
}
},
GL15_MAP {
@Override
public boolean supported(GLCapabilities caps) {
return caps.OpenGL15;
}
@Override
public void mapBuffer(GlBufferType target, int offset, int length, Consumer<ByteBuffer> upload) {
ByteBuffer buffer = GL15.glMapBuffer(target.glEnum, GL15.GL_WRITE_ONLY);
buffer.position(offset);
upload.accept(buffer);
buffer.rewind();
GL15.glUnmapBuffer(target.glEnum);
}
},
UNSUPPORTED {
@Override
public boolean supported(GLCapabilities caps) {
return true;
}
@Override
public void mapBuffer(GlBufferType target, int offset, int length, Consumer<ByteBuffer> upload) {
throw new UnsupportedOperationException("glMapBuffer not supported");
}
@Override
public void unmapBuffer(int target) {
throw new UnsupportedOperationException("glMapBuffer not supported");
}
};
public void unmapBuffer(int target) {
GL15.glUnmapBuffer(target);
}
public abstract void mapBuffer(GlBufferType target, int offset, int length, Consumer<ByteBuffer> upload);
}

View file

@ -0,0 +1,49 @@
package com.jozufozu.flywheel.backend.gl.versioned;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.ARBMapBufferRange;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GLCapabilities;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
public enum MapBufferRange implements GlVersioned {
GL30_RANGE {
@Override
public boolean supported(GLCapabilities caps) {
return caps.OpenGL30;
}
@Override
public ByteBuffer mapBuffer(GlBufferType target, long offset, long length, int access) {
return GL30.glMapBufferRange(target.glEnum, offset, length, access);
}
},
ARB_RANGE {
@Override
public boolean supported(GLCapabilities caps) {
return caps.GL_ARB_map_buffer_range;
}
@Override
public ByteBuffer mapBuffer(GlBufferType target, long offset, long length, int access) {
return ARBMapBufferRange.glMapBufferRange(target.glEnum, offset, length, access);
}
},
UNSUPPORTED {
@Override
public boolean supported(GLCapabilities caps) {
return true;
}
@Override
public ByteBuffer mapBuffer(GlBufferType target, long offset, long length, int access) {
throw new UnsupportedOperationException("glMapBuffer not supported");
}
};
public abstract ByteBuffer mapBuffer(GlBufferType target, long offset, long length, int access);
}

View file

@ -1,6 +1,6 @@
package com.jozufozu.flywheel.backend.instancing;
import com.jozufozu.flywheel.backend.gl.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
public abstract class InstanceData {

View file

@ -9,11 +9,11 @@ import org.lwjgl.opengl.GL11;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.BufferedModel;
import com.jozufozu.flywheel.backend.core.materials.ModelAttributes;
import com.jozufozu.flywheel.backend.gl.GlBuffer;
import com.jozufozu.flywheel.backend.gl.GlBufferType;
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
import com.jozufozu.flywheel.backend.gl.MappedBufferRange;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import net.minecraft.client.renderer.BufferBuilder;
@ -128,9 +128,9 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
final int offset = size * getInstanceFormat().getStride();
final int length = glBufferSize - offset;
if (length > 0) {
MappedBufferRange buffer = instanceVBO.getBuffer(offset, length);
MappedBuffer buffer = instanceVBO.getBuffer(offset, length);
buffer.putByteArray(new byte[length]);
buffer.unmap();
buffer.flush();
}
}
@ -151,14 +151,15 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
final int length = (1 + lastDirty - firstDirty) * stride;
if (length > 0) {
MappedBufferRange mapped = instanceVBO.getBuffer(offset, length);
MappedBuffer mapped = instanceVBO.getBuffer(offset, length);
dirtySet.stream().forEach(i -> {
final D d = data.get(i);
mapped.position(i * stride - offset);
mapped.position(i * stride);
d.write(mapped);
});
mapped.unmap();
mapped.flush();
}
}
@ -185,11 +186,11 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
glBufferSize = requiredSize + stride * 16;
instanceVBO.alloc(glBufferSize);
MappedBufferRange buffer = instanceVBO.getBuffer(0, glBufferSize);
MappedBuffer buffer = instanceVBO.getBuffer(0, glBufferSize);
for (D datum : data) {
datum.write(buffer);
}
buffer.unmap();
buffer.flush();
glInstanceCount = size;
return true;
@ -232,7 +233,7 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
}
@Override
protected void copyVertex(MappedBufferRange constant, int i) {
protected void copyVertex(MappedBuffer constant, int i) {
constant.putFloat(getX(template, i));
constant.putFloat(getY(template, i));
constant.putFloat(getZ(template, i));

View file

@ -1,7 +1,7 @@
package com.simibubi.create.content.contraptions.base;
import com.jozufozu.flywheel.backend.core.materials.BasicData;
import com.jozufozu.flywheel.backend.gl.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.backend.instancing.InstancedModel;
import com.simibubi.create.foundation.utility.ColorHelper;

View file

@ -1,6 +1,6 @@
package com.simibubi.create.content.contraptions.base;
import com.jozufozu.flywheel.backend.gl.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.backend.instancing.InstancedModel;
import net.minecraft.util.Direction;

View file

@ -1,6 +1,6 @@
package com.simibubi.create.content.contraptions.components.actors;
import com.jozufozu.flywheel.backend.gl.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.backend.instancing.InstanceData;
import com.jozufozu.flywheel.backend.instancing.InstancedModel;

View file

@ -3,11 +3,11 @@ package com.simibubi.create.content.contraptions.components.structureMovement.re
import org.lwjgl.opengl.GL20;
import com.jozufozu.flywheel.backend.BufferedModel;
import com.jozufozu.flywheel.backend.gl.GlBuffer;
import com.jozufozu.flywheel.backend.gl.GlBufferType;
import com.jozufozu.flywheel.backend.gl.GlPrimitiveType;
import com.jozufozu.flywheel.backend.gl.MappedBufferRange;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.LightTexture;
@ -57,17 +57,17 @@ public class ContraptionModel extends BufferedModel {
ebo.bind();
ebo.alloc(indicesSize);
MappedBufferRange indices = ebo.getBuffer(0, indicesSize);
MappedBuffer indices = ebo.getBuffer(0, indicesSize);
for (int i = 0; i < vertexCount; i++) {
indices.putInt(i);
}
indices.unmap();
indices.flush();
ebo.unbind();
}
@Override
protected void copyVertex(MappedBufferRange to, int vertex) {
protected void copyVertex(MappedBuffer to, int vertex) {
to.putFloat(getX(template, vertex));
to.putFloat(getY(template, vertex));
to.putFloat(getZ(template, vertex));

View file

@ -1,6 +1,6 @@
package com.simibubi.create.content.contraptions.relays.belt;
import com.jozufozu.flywheel.backend.gl.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.backend.instancing.InstancedModel;
import com.simibubi.create.content.contraptions.base.KineticData;
import com.simibubi.create.foundation.block.render.SpriteShiftEntry;

View file

@ -1,7 +1,7 @@
package com.simibubi.create.content.logistics.block;
import com.jozufozu.flywheel.backend.core.materials.IFlatLight;
import com.jozufozu.flywheel.backend.gl.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.backend.instancing.InstanceData;
import com.jozufozu.flywheel.backend.instancing.InstancedModel;

View file

@ -9,11 +9,11 @@ import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlBuffer;
import com.jozufozu.flywheel.backend.gl.GlBufferType;
import com.jozufozu.flywheel.backend.gl.GlPrimitiveType;
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
import com.jozufozu.flywheel.backend.gl.MappedBufferRange;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.util.RenderUtil;
import com.simibubi.create.foundation.render.AllProgramSpecs;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
@ -81,9 +81,9 @@ public class EffectsHandler {
vbo.bind();
vbo.alloc(bufferSize);
MappedBufferRange buffer = vbo.getBuffer(0, bufferSize);
MappedBuffer buffer = vbo.getBuffer(0, bufferSize);
buffer.putFloatArray(vertices);
buffer.unmap();
buffer.flush();
vao.bind();

View file

@ -1,6 +1,6 @@
package com.simibubi.create.foundation.render.effects;
import com.jozufozu.flywheel.backend.gl.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.util.RenderUtil;
import net.minecraft.util.math.vector.Matrix4f;

View file

@ -5,9 +5,9 @@ import java.util.ArrayList;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL31;
import com.jozufozu.flywheel.backend.gl.GlBuffer;
import com.jozufozu.flywheel.backend.gl.GlBufferType;
import com.jozufozu.flywheel.backend.gl.MappedBufferRange;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import net.minecraft.util.ResourceLocation;
@ -81,13 +81,13 @@ public class SphereFilterProgram extends GlProgram {
public void uploadFilters(ArrayList<FilterSphere> filters) {
effectsUBO.bind(GlBufferType.ARRAY_BUFFER);
MappedBufferRange buffer = effectsUBO.getBuffer(0, BUFFER_SIZE);
MappedBuffer buffer = effectsUBO.getBuffer(0, BUFFER_SIZE);
buffer.putInt(filters.size())
.position(16);
filters.forEach(it -> it.write(buffer));
buffer.unmap();
buffer.flush();
effectsUBO.unbind(GlBufferType.ARRAY_BUFFER);
}