Errors and pools

- GlException and error checking WIP
 - Put all models within a material in a ModelPool
 - Instancers directly accept IModels
 - ModelPools are very WIP
This commit is contained in:
Jozufozu 2021-08-20 15:05:41 -07:00
parent f4f6087e08
commit 2137f9e46d
20 changed files with 513 additions and 69 deletions

View file

@ -1,6 +1,8 @@
package com.jozufozu.flywheel.backend.gl.attrib;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL44;
import org.lwjgl.opengl.GL46;
import com.jozufozu.flywheel.backend.gl.GlNumericType;

View file

@ -1,6 +1,9 @@
package com.jozufozu.flywheel.backend.gl.buffer;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.error.GlError;
import com.jozufozu.flywheel.backend.gl.error.GlException;
import com.jozufozu.flywheel.util.StringUtil;
public class MappedBufferRange extends MappedBuffer {
@ -27,6 +30,12 @@ public class MappedBufferRange extends MappedBuffer {
protected void checkAndMap() {
if (!mapped) {
setInternal(Backend.getInstance().compat.mapBufferRange.mapBuffer(owner.type, offset, length, access));
GlError error = GlError.poll();
if (error != null) {
throw new GlException(error, StringUtil.args("mapBufferRange", owner.type, offset, length, access));
}
mapped = true;
}
}

View file

@ -2,6 +2,10 @@ package com.jozufozu.flywheel.backend.gl.buffer;
import org.lwjgl.opengl.GL15;
import com.jozufozu.flywheel.backend.gl.error.GlError;
import com.jozufozu.flywheel.backend.gl.error.GlException;
import com.jozufozu.flywheel.util.StringUtil;
public class MappedFullBuffer extends MappedBuffer {
MappedBufferUsage usage;
@ -15,6 +19,13 @@ public class MappedFullBuffer extends MappedBuffer {
protected void checkAndMap() {
if (!mapped) {
setInternal(GL15.glMapBuffer(owner.type.glEnum, usage.glEnum));
GlError error = GlError.poll();
if (error != null) {
throw new GlException(error, StringUtil.args("mapBuffer", owner.type, usage));
}
mapped = true;
}
}

View file

@ -6,6 +6,9 @@ import java.nio.ByteBuffer;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlFence;
import com.jozufozu.flywheel.backend.gl.error.GlError;
import com.jozufozu.flywheel.backend.gl.error.GlException;
import com.jozufozu.flywheel.util.StringUtil;
public class PersistentGlBuffer extends GlBuffer {
@ -35,11 +38,19 @@ public class PersistentGlBuffer extends GlBuffer {
if (buffer != null) {
deleteInternal(handle());
_create();
bind();
}
fence.clear();
Backend.getInstance().compat.bufferStorage.bufferStorage(type.glEnum, size, flags);
Backend.getInstance().compat.bufferStorage.bufferStorage(type, size, flags);
GlError error = GlError.poll();
if (error != null) {
throw new GlException(error, StringUtil.args("bufferStorage", type, size, flags));
}
buffer = new PersistentMappedBuffer(this);
}

View file

@ -2,25 +2,42 @@ package com.jozufozu.flywheel.backend.gl.buffer;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL44;
import org.lwjgl.opengl.GL46;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.error.GlError;
import com.jozufozu.flywheel.backend.gl.error.GlException;
import com.jozufozu.flywheel.util.StringUtil;
public class PersistentMappedBuffer extends MappedBuffer {
private final long offset;
private final long length;
PersistentGlBuffer owner;
public PersistentMappedBuffer(PersistentGlBuffer buffer) {
super(buffer);
owner = buffer;
offset = 0;
length = owner.size;
ByteBuffer byteBuffer = Backend.getInstance().compat.mapBufferRange.mapBuffer(owner.type, 0, owner.size, owner.flags);
ByteBuffer byteBuffer = Backend.getInstance().compat.mapBufferRange.mapBuffer(owner.type, offset, length, owner.flags);
GlError error = GlError.poll();
if (error != null) {
throw new GlException(error, StringUtil.args("mapBuffer", owner.type, offset, length, owner.flags));
}
setInternal(byteBuffer);
}
@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
public void flush() {

View file

@ -0,0 +1,38 @@
package com.jozufozu.flywheel.backend.gl.error;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
public enum GlError {
INVALID_ENUM(GL20.GL_INVALID_ENUM),
INVALID_VALUE(GL20.GL_INVALID_VALUE),
INVALID_OPERATION(GL20.GL_INVALID_OPERATION),
INVALID_FRAMEBUFFER_OPERATION(GL30.GL_INVALID_FRAMEBUFFER_OPERATION),
OUT_OF_MEMORY(GL20.GL_OUT_OF_MEMORY),
STACK_UNDERFLOW(GL20.GL_STACK_UNDERFLOW),
STACK_OVERFLOW(GL20.GL_STACK_OVERFLOW),
;
private static final Int2ObjectMap<GlError> errorLookup = new Int2ObjectArrayMap<>();
static {
errorLookup.defaultReturnValue(null);
for (GlError value : values()) {
errorLookup.put(value.glEnum, value);
}
}
final int glEnum;
GlError(int glEnum) {
this.glEnum = glEnum;
}
public static GlError poll() {
return errorLookup.get(GL20.glGetError());
}
}

View file

@ -0,0 +1,38 @@
package com.jozufozu.flywheel.backend.gl.error;
public class GlException extends RuntimeException {
final GlError errorCode;
@Override
public String toString() {
String s = getClass().getName();
String message = getLocalizedMessage();
String withCode = s + ": " + errorCode;
return (message != null) ? (withCode + ": " + message) : withCode;
}
public GlException(GlError errorCode) {
this.errorCode = errorCode;
}
public GlException(GlError errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public GlException(GlError errorCode, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
}
public GlException(GlError errorCode, Throwable cause) {
super(cause);
this.errorCode = errorCode;
}
public GlException(GlError errorCode, String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
this.errorCode = errorCode;
}
}

View file

@ -4,6 +4,8 @@ import org.lwjgl.opengl.ARBBufferStorage;
import org.lwjgl.opengl.GL44;
import org.lwjgl.opengl.GLCapabilities;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
public enum BufferStorage implements GlVersioned {
GL44CORE {
@ -13,8 +15,8 @@ public enum BufferStorage implements GlVersioned {
}
@Override
public void bufferStorage(int target, long size, int flags) {
GL44.glBufferStorage(target, size, flags);
public void bufferStorage(GlBufferType target, long size, int flags) {
GL44.glBufferStorage(target.glEnum, size, flags);
}
},
ARB {
@ -24,8 +26,8 @@ public enum BufferStorage implements GlVersioned {
}
@Override
public void bufferStorage(int target, long size, int flags) {
ARBBufferStorage.glBufferStorage(target, size, flags);
public void bufferStorage(GlBufferType target, long size, int flags) {
ARBBufferStorage.glBufferStorage(target.glEnum, size, flags);
}
},
UNSUPPORTED {
@ -35,10 +37,10 @@ public enum BufferStorage implements GlVersioned {
}
@Override
public void bufferStorage(int target, long size, int flags) {
public void bufferStorage(GlBufferType target, long size, int flags) {
throw new UnsupportedOperationException();
}
};
public abstract void bufferStorage(int target, long size, int flags);
public abstract void bufferStorage(GlBufferType target, long size, int flags);
}

View file

@ -12,6 +12,7 @@ import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.backend.gl.versioned.framebuffer.Blit;
import com.jozufozu.flywheel.backend.gl.versioned.framebuffer.Framebuffer;
import com.jozufozu.flywheel.backend.gl.versioned.instancing.DrawInstanced;
import com.jozufozu.flywheel.backend.gl.versioned.instancing.BaseVertex;
import com.jozufozu.flywheel.backend.gl.versioned.instancing.InstancedArrays;
import com.jozufozu.flywheel.backend.gl.versioned.instancing.VertexArrayObject;
@ -32,6 +33,7 @@ public class GlCompat {
public final BufferStorage bufferStorage;
public final RGPixelFormat pixelFormat;
public final BaseVertex baseVertex;
public GlCompat(GLCapabilities caps) {
mapBufferRange = getLatest(MapBufferRange.class, caps);
@ -39,6 +41,7 @@ public class GlCompat {
vao = getLatest(VertexArrayObject.class, caps);
instancedArrays = getLatest(InstancedArrays.class, caps);
drawInstanced = getLatest(DrawInstanced.class, caps);
baseVertex = getLatest(BaseVertex.class, caps);
blit = getLatest(Blit.class, caps);
fbo = getLatest(Framebuffer.class, caps);
bufferStorage = getLatest(BufferStorage.class, caps);

View file

@ -0,0 +1,62 @@
package com.jozufozu.flywheel.backend.gl.versioned.instancing;
import org.lwjgl.opengl.ARBDrawElementsBaseVertex;
import org.lwjgl.opengl.ARBDrawInstanced;
import org.lwjgl.opengl.EXTDrawInstanced;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GLCapabilities;
import com.jozufozu.flywheel.backend.gl.GlNumericType;
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
import com.jozufozu.flywheel.backend.gl.versioned.GlVersioned;
public enum BaseVertex implements GlVersioned {
GL31_CORE {
@Override
public boolean supported(GLCapabilities caps) {
return caps.OpenGL31;
}
@Override
public void drawElementsInstancedBaseVertex(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int instanceCount, int baseVertex) {
GL32.glDrawElementsInstancedBaseVertex(mode.glEnum, elementCount, type.getGlEnum(), indices, instanceCount, baseVertex);
}
@Override
public void drawElementsBaseVertex(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int baseVertex) {
GL32.glDrawElementsBaseVertex(mode.glEnum, elementCount, type.getGlEnum(), indices, baseVertex);
}
},
ARB {
@Override
public boolean supported(GLCapabilities caps) {
return caps.GL_ARB_draw_elements_base_vertex;
}
@Override
public void drawElementsInstancedBaseVertex(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int instanceCount, int baseVertex) {
ARBDrawElementsBaseVertex.glDrawElementsInstancedBaseVertex(mode.glEnum, elementCount, type.getGlEnum(), indices, instanceCount, baseVertex);
}
@Override
public void drawElementsBaseVertex(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int baseVertex) {
ARBDrawElementsBaseVertex.glDrawElementsBaseVertex(mode.glEnum, elementCount, type.getGlEnum(), indices, baseVertex);
}
},
UNSUPPORTED {
@Override
public boolean supported(GLCapabilities caps) {
return true;
}
};
public void drawElementsInstancedBaseVertex(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int instanceCount, int baseVertex) {
throw new UnsupportedOperationException();
}
public void drawElementsBaseVertex(GlPrimitive mode, int elementCount, GlNumericType type, long indices, int baseVertex) {
throw new UnsupportedOperationException();
}
}

View file

@ -3,6 +3,7 @@ package com.jozufozu.flywheel.backend.gl.versioned.instancing;
import org.lwjgl.opengl.ARBDrawInstanced;
import org.lwjgl.opengl.EXTDrawInstanced;
import org.lwjgl.opengl.GL31;
import org.lwjgl.opengl.GL46;
import org.lwjgl.opengl.GLCapabilities;
import com.jozufozu.flywheel.backend.gl.GlNumericType;
@ -10,7 +11,7 @@ import com.jozufozu.flywheel.backend.gl.GlPrimitive;
import com.jozufozu.flywheel.backend.gl.versioned.GlVersioned;
public enum DrawInstanced implements GlVersioned {
GL31_DRAW_INSTANCED {
GL31_CORE {
@Override
public boolean supported(GLCapabilities caps) {
return caps.OpenGL31;
@ -26,7 +27,7 @@ public enum DrawInstanced implements GlVersioned {
GL31.glDrawElementsInstanced(mode.glEnum, elementCount, type.getGlEnum(), indices, primcount);
}
},
ARB_DRAW_INSTANCED {
ARB {
@Override
public boolean supported(GLCapabilities caps) {
return caps.GL_ARB_draw_instanced;
@ -42,7 +43,7 @@ public enum DrawInstanced implements GlVersioned {
ARBDrawInstanced.glDrawElementsInstancedARB(mode.glEnum, elementCount, type.getGlEnum(), indices, primcount);
}
},
EXT_DRAW_INSTANCED {
EXT {
@Override
public boolean supported(GLCapabilities caps) {
return caps.GL_EXT_draw_instanced;

View file

@ -2,7 +2,6 @@ package com.jozufozu.flywheel.backend.instancing;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.function.Supplier;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
@ -11,8 +10,8 @@ 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.material.MaterialSpec;
import com.jozufozu.flywheel.backend.model.ModelPool;
import com.jozufozu.flywheel.backend.model.IBufferedModel;
import com.jozufozu.flywheel.backend.model.IndexedModel;
import com.jozufozu.flywheel.core.model.IModel;
import com.jozufozu.flywheel.util.AttribUtil;
@ -36,25 +35,27 @@ import com.jozufozu.flywheel.util.AttribUtil;
*/
public class Instancer<D extends InstanceData> {
protected final Supplier<IModel> gen;
protected final VertexFormat instanceFormat;
protected final IInstanceFactory<D> factory;
private final ModelPool modelAllocator;
private final IModel modelData;
private final VertexFormat instanceFormat;
private final IInstanceFactory<D> factory;
protected IBufferedModel model;
protected GlVertexArray vao;
protected GlBuffer instanceVBO;
protected int glBufferSize = -1;
protected int glInstanceCount = 0;
private IBufferedModel model;
private GlVertexArray vao;
private GlBuffer instanceVBO;
private int glBufferSize = -1;
private int glInstanceCount = 0;
private boolean deleted;
private boolean initialized;
protected final ArrayList<D> data = new ArrayList<>();
private final ArrayList<D> data = new ArrayList<>();
boolean anyToRemove;
boolean anyToUpdate;
public Instancer(Supplier<IModel> model, MaterialSpec<D> spec) {
this.gen = model;
public Instancer(ModelPool modelAllocator, IModel model, MaterialSpec<D> spec) {
this.modelAllocator = modelAllocator;
this.modelData = model;
this.factory = spec.getInstanceFactory();
this.instanceFormat = spec.getInstanceFormat();
}
@ -80,7 +81,6 @@ public class Instancer<D extends InstanceData> {
}
public void render() {
if (!isInitialized()) init();
if (invalid()) return;
vao.bind();
@ -98,28 +98,28 @@ public class Instancer<D extends InstanceData> {
return deleted || model == null;
}
private void init() {
public void init() {
if (isInitialized()) return;
initialized = true;
IModel iModel = gen.get();
if (iModel.empty()) {
return;
}
model = new IndexedModel(iModel);
vao = new GlVertexArray();
instanceVBO = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER);
model = modelAllocator.alloc(modelData)
.setReallocCallback(arenaModel -> {
vao.bind();
model.setupState();
vao.unbind();
});
vao.bind();
// bind the model's vbo to our vao
model.setupState();
instanceVBO = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER);
AttribUtil.enableArrays(model.getAttributeCount() + instanceFormat.getAttributeCount());
vao.unbind();
model.clearState();
}
public boolean isInitialized() {

View file

@ -1,7 +1,6 @@
package com.jozufozu.flywheel.backend.material;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.function.Supplier;
import com.google.common.cache.Cache;
@ -9,6 +8,7 @@ import com.google.common.cache.CacheBuilder;
import com.jozufozu.flywheel.backend.RenderWork;
import com.jozufozu.flywheel.backend.instancing.InstanceData;
import com.jozufozu.flywheel.backend.instancing.Instancer;
import com.jozufozu.flywheel.backend.model.ModelPool;
import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.core.model.BlockModel;
import com.jozufozu.flywheel.core.model.IModel;
@ -25,12 +25,14 @@ import net.minecraft.util.Direction;
*/
public class InstanceMaterial<D extends InstanceData> {
final ModelPool modelPool;
protected final Cache<Object, Instancer<D>> models;
protected final MaterialSpec<D> spec;
public InstanceMaterial(MaterialSpec<D> spec) {
this.spec = spec;
modelPool = new ModelPool(spec.getModelFormat(), spec.getModelFormat().getStride() * 64);
this.models = CacheBuilder.newBuilder()
.removalListener(notification -> {
Instancer<?> instancer = (Instancer<?>) notification.getValue();
@ -48,7 +50,7 @@ public class InstanceMaterial<D extends InstanceData> {
*/
public Instancer<D> model(Object key, Supplier<IModel> modelSupplier) {
try {
return models.get(key, () -> new Instancer<>(modelSupplier, spec));
return models.get(key, () -> new Instancer<>(modelPool, modelSupplier.get(), spec));
} catch (ExecutionException e) {
throw new RuntimeException("error creating instancer", e);
}
@ -79,6 +81,7 @@ public class InstanceMaterial<D extends InstanceData> {
public void delete() {
models.invalidateAll();
modelPool.delete();
}
/**
@ -90,11 +93,4 @@ public class InstanceMaterial<D extends InstanceData> {
.forEach(Instancer::clear);
}
public void forEachInstancer(Consumer<Instancer<D>> f) {
for (Instancer<D> model : models.asMap()
.values()) {
f.accept(model);
}
}
}

View file

@ -17,7 +17,6 @@ import com.jozufozu.flywheel.core.shader.WorldProgram;
import com.jozufozu.flywheel.util.WeakHashSet;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.inventory.container.PlayerContainer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;

View file

@ -1,5 +1,6 @@
package com.jozufozu.flywheel.backend.material;
import java.util.Collection;
import java.util.function.Consumer;
import java.util.function.Supplier;
@ -24,6 +25,14 @@ public class MaterialRenderer<P extends WorldProgram> {
public void render(Matrix4f viewProjection, double camX, double camY, double camZ) {
if (material.nothingToRender()) return;
Collection<? extends Instancer<?>> instancers = material.models.asMap()
.values();
// initialize all uninitialized instancers...
instancers.forEach(Instancer::init);
// ...and then flush the model arena in case anything was marked for upload
material.modelPool.flush();
P program = this.program.get();
program.bind();
@ -32,7 +41,7 @@ public class MaterialRenderer<P extends WorldProgram> {
setupFunc.accept(program);
material.forEachInstancer(Instancer::render);
instancers.forEach(Instancer::render);
}
}

View file

@ -2,6 +2,8 @@ package com.jozufozu.flywheel.backend.model;
import static org.lwjgl.opengl.GL20.glDrawArrays;
import org.lwjgl.opengl.GL44;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
@ -37,6 +39,10 @@ public class BufferedModel implements IBufferedModel {
vbo.unbind();
}
public boolean isDeleted() {
return deleted;
}
public VertexFormat getFormat() {
return model.format();
}
@ -45,10 +51,6 @@ public class BufferedModel implements IBufferedModel {
return model.vertexCount();
}
public boolean valid() {
return getVertexCount() > 0 && !deleted;
}
/**
* The VBO/VAO should be bound externally.
*/

View file

@ -8,8 +8,6 @@ public interface IBufferedModel {
int getVertexCount();
boolean valid();
/**
* The VBO/VAO should be bound externally.
*/
@ -24,8 +22,14 @@ public interface IBufferedModel {
*/
void drawInstances(int instanceCount);
boolean isDeleted();
void delete();
default boolean valid() {
return getVertexCount() > 0 && !isDeleted();
}
default int getAttributeCount() {
return getFormat().getAttributeCount();
}

View file

@ -0,0 +1,229 @@
package com.jozufozu.flywheel.backend.model;
import java.util.ArrayList;
import java.util.List;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
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.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer;
import com.jozufozu.flywheel.core.model.IModel;
import com.jozufozu.flywheel.util.AttribUtil;
import com.jozufozu.flywheel.util.StringUtil;
public class ModelPool {
protected final VertexFormat format;
private final List<PooledModel> models = new ArrayList<>();
private final List<PooledModel> pendingUpload = new ArrayList<>();
private final GlBuffer vbo;
private int bufferSize;
private int vertices;
private boolean dirty;
private boolean anyToRemove;
public ModelPool(VertexFormat format, int initialSize) {
this.format = format;
bufferSize = initialSize;
vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER);
vbo.bind();
vbo.alloc(bufferSize);
vbo.unbind();
}
/**
* Allocate a model in the arena.
*
* @param model The model to allocate.
* @return A handle to the allocated model.
*/
public PooledModel alloc(IModel model) {
PooledModel bufferedModel = new PooledModel(model, vertices);
vertices += model.vertexCount();
models.add(bufferedModel);
pendingUpload.add(bufferedModel);
setDirty();
return bufferedModel;
}
public void flush() {
if (dirty) {
if (anyToRemove) processDeletions();
vbo.bind();
if (realloc()) {
uploadAll();
} else {
uploadPending();
}
vbo.unbind();
dirty = false;
pendingUpload.clear();
}
}
private void processDeletions() {
// remove deleted models
models.removeIf(PooledModel::isDeleted);
// re-evaluate first vertex for each model
int vertices = 0;
for (PooledModel model : models) {
if (model.first != vertices)
pendingUpload.add(model);
model.first = vertices;
vertices += model.getVertexCount();
}
this.vertices = vertices;
this.anyToRemove = false;
}
/**
* Assumes vbo is bound.
*
* @return true if the buffer was reallocated
*/
private boolean realloc() {
int neededSize = vertices * format.getStride();
if (neededSize > bufferSize) {
bufferSize = neededSize + 128;
vbo.alloc(bufferSize);
return true;
}
return false;
}
private void uploadAll() {
MappedBuffer buffer = vbo.getBuffer(0, bufferSize);
for (PooledModel model : models) {
model.model.buffer(buffer);
if (model.callback != null)
model.callback.invoke(model);
}
buffer.flush();
}
private void uploadPending() {
MappedBuffer buffer = vbo.getBuffer(0, bufferSize);
int stride = format.getStride();
for (PooledModel model : pendingUpload) {
int pos = model.first * stride;
buffer.position(pos);
model.model.buffer(buffer);
if (model.callback != null)
model.callback.invoke(model);
}
pendingUpload.clear();
buffer.flush();
}
private void setDirty() {
dirty = true;
}
public void delete() {
vbo.delete();
}
public class PooledModel implements IBufferedModel {
private final ElementBuffer ebo;
private Callback callback;
private final IModel model;
private int first;
private boolean remove;
public PooledModel(IModel model, int first) {
this.model = model;
this.first = first;
ebo = model.createEBO();
}
@Override
public VertexFormat getFormat() {
return model.format();
}
@Override
public int getVertexCount() {
return model.vertexCount();
}
@Override
public void setupState() {
vbo.bind();
ebo.bind();
AttribUtil.enableArrays(getAttributeCount());
getFormat().vertexAttribPointers(0);
}
@Override
public void clearState() {
AttribUtil.disableArrays(getAttributeCount());
ebo.unbind();
vbo.unbind();
}
@Override
public void drawCall() {
Backend.getInstance().compat.baseVertex.drawElementsBaseVertex(GlPrimitive.TRIANGLES, ebo.elementCount, ebo.eboIndexType, 0, first);
}
@Override
public void drawInstances(int instanceCount) {
if (!valid()) return;
ebo.bind();
Backend.log.info(StringUtil.args("drawElementsInstancedBaseVertex", GlPrimitive.TRIANGLES, ebo.elementCount, ebo.eboIndexType, 0, instanceCount, first));
Backend.getInstance().compat.baseVertex.drawElementsInstancedBaseVertex(GlPrimitive.TRIANGLES, ebo.elementCount, ebo.eboIndexType, 0, instanceCount, first);
}
@Override
public boolean isDeleted() {
return false;
}
@Override
public void delete() {
setDirty();
anyToRemove = true;
remove = true;
}
public PooledModel setReallocCallback(Callback callback) {
this.callback = callback;
return this;
}
}
@FunctionalInterface
public interface Callback {
void invoke(PooledModel arenaModel);
}
}

View file

@ -30,14 +30,14 @@ import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber(Dist.CLIENT)
public class QuadConverter {
public static final int STARTING_CAPACITY = 42;
public static final int STARTING_CAPACITY = 42; // 255 / 6 = 42
private static QuadConverter INSTANCE;
@Nonnull
public static QuadConverter getInstance() {
if (INSTANCE == null) {
INSTANCE = new QuadConverter(STARTING_CAPACITY); // 255 / 6 = 42
INSTANCE = new QuadConverter(STARTING_CAPACITY);
}
return INSTANCE;
@ -157,14 +157,14 @@ public class QuadConverter {
* </pre>
*/
private static GlNumericType getSmallestIndexType(int indexCount) {
indexCount = indexCount >>> 8;
if (indexCount == 0) {
return GlNumericType.UBYTE;
}
indexCount = indexCount >>> 8;
if (indexCount == 0) {
return GlNumericType.USHORT;
}
// indexCount = indexCount >>> 8;
// if (indexCount == 0) {
// return GlNumericType.UBYTE;
// }
// indexCount = indexCount >>> 8;
// if (indexCount == 0) {
// return GlNumericType.USHORT;
// }
return GlNumericType.UINT;
}

View file

@ -1,6 +1,17 @@
package com.jozufozu.flywheel.util;
import java.util.Arrays;
import java.util.stream.Collectors;
public class StringUtil {
public static String args(String functionName, Object... args) {
return functionName + '(' + Arrays.stream(args)
.map(Object::toString)
.collect(Collectors.joining(", ")) + ')';
}
public static String trimEnd(String value) {
int len = value.length();
int st = 0;