Go through GlVertexArray

- VAO state is now handled by GlVertexArray objects
 - IndexedModel no longer inherits from VBOModel
 - BufferedModel doesn't need #clearState
 - Likely fixes crash on intel drivers
This commit is contained in:
Jozufozu 2021-12-27 19:14:19 -08:00
parent 4c4d6b77fc
commit b5a9741caf
11 changed files with 137 additions and 162 deletions

View file

@ -18,9 +18,7 @@ public abstract class GlObject {
protected final void checkHandle() {
if (this.isInvalid()) {
String descriptor = getDescriptor();
String message = (descriptor == null ? "" : (descriptor + " ")) + "handle is not valid.";
throw new IllegalStateException(message);
throw new IllegalStateException("handle is not valid.");
}
}
@ -33,10 +31,8 @@ public abstract class GlObject {
}
public void delete() {
if (isInvalid()) {
String descriptor = getDescriptor();
String message = (descriptor == null ? "" : (descriptor + " ")) + "handle already deleted.";
throw new IllegalStateException(message);
if (this.isInvalid()) {
throw new IllegalStateException("handle already deleted.");
}
deleteInternal(handle);
@ -45,7 +41,4 @@ public abstract class GlObject {
protected abstract void deleteInternal(int handle);
protected String getDescriptor() {
return "";
}
}

View file

@ -1,7 +1,10 @@
package com.jozufozu.flywheel.backend.gl;
import org.lwjgl.opengl.GL20;
import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.jozufozu.flywheel.core.layout.LayoutItem;
import com.jozufozu.flywheel.mixin.BufferUploaderAccessor;
import com.jozufozu.flywheel.util.AttribUtil;
import com.mojang.blaze3d.platform.GlStateManager;
public class GlVertexArray extends GlObject {
@ -20,11 +23,28 @@ public class GlVertexArray extends GlObject {
BufferUploaderAccessor.flywheel$setLastVAO(0);
}
public void enableArrays(int count) {
for (int i = 0; i < count; i++) {
GL20.glEnableVertexAttribArray(i);
}
}
public void disableArrays(int count) {
for (int i = 0; i < count; i++) {
GL20.glDisableVertexAttribArray(i);
}
}
public void bindAttributes(int startIndex, BufferLayout type) {
int offset = 0;
for (LayoutItem spec : type.getLayoutItems()) {
spec.vertexAttribPointer(type.getStride(), startIndex, offset);
startIndex += spec.getAttributeCount();
offset += spec.getSize();
}
}
protected void deleteInternal(int handle) {
GlStateManager._glDeleteVertexArrays(handle);
}
public void enableArrays(int count) {
AttribUtil.enableArrays(count);
}
}

View file

@ -8,13 +8,13 @@ import com.jozufozu.flywheel.api.struct.Instanced;
import com.jozufozu.flywheel.api.struct.StructWriter;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
import com.jozufozu.flywheel.core.layout.BufferLayout;
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.instancing.AbstractInstancer;
import com.jozufozu.flywheel.backend.model.BufferedModel;
import com.jozufozu.flywheel.backend.model.ModelAllocator;
import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.jozufozu.flywheel.core.model.Model;
public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
@ -73,14 +73,14 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
model = modelAllocator.alloc(modelData, arenaModel -> {
vao.bind();
arenaModel.setupState();
arenaModel.setupState(vao);
});
vao.bind();
vao.enableArrays(model.getAttributeCount() + instanceFormat.getAttributeCount());
instanceVBO = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER);
instanceVBO.setGrowthMargin(instanceFormat.getStride() * 16);
vao.enableArrays(model.getAttributeCount() + instanceFormat.getAttributeCount());
}
public boolean isInitialized() {
@ -180,19 +180,19 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
glInstanceCount = size;
informAttribDivisors();
bindInstanceAttributes();
return true;
}
return false;
}
private void informAttribDivisors() {
int staticAttributes = model.getAttributeCount();
instanceFormat.vertexAttribPointers(staticAttributes);
private void bindInstanceAttributes() {
int attributeBaseIndex = model.getAttributeCount();
vao.bindAttributes(attributeBaseIndex, instanceFormat);
for (int i = 0; i < instanceFormat.getAttributeCount(); i++) {
Backend.getInstance().compat.instancedArrays.vertexAttribDivisor(i + staticAttributes, 1);
Backend.getInstance().compat.instancedArrays.vertexAttribDivisor(attributeBaseIndex + i, 1);
}
}
}

View file

@ -1,46 +1,54 @@
package com.jozufozu.flywheel.backend.model;
import java.util.function.Supplier;
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
import com.jozufozu.flywheel.core.model.Model;
public class ArrayModelRenderer extends ModelRenderer {
public class ArrayModelRenderer {
private final Model model;
protected GlVertexArray vao;
protected BufferedModel vbo;
protected boolean initialized;
public ArrayModelRenderer(Supplier<Model> model) {
super(model);
public ArrayModelRenderer(Model model) {
this.model = model;
}
@Override
/**
* Renders this model, checking first if there is anything to render.
*/
public void draw() {
if (!initialized) init();
if (!isValid()) return;
vao.bind();
model.drawCall();
vbo.drawCall();
}
@Override
protected void init() {
initialized = true;
Model model = modelSupplier.get();
if (model.empty()) return;
this.model = new IndexedModel(model);
this.vbo = new IndexedModel(model);
vao = new GlVertexArray();
vao.bind();
// bind the model's vbo to our vao
this.model.setupState();
this.vbo.setupState(vao);
GlVertexArray.unbind();
}
this.model.clearState();
public void delete() {
if (vbo != null)
vbo.delete();
}
protected boolean isValid() {
return vbo != null && vbo.valid();
}
}

View file

@ -1,7 +1,8 @@
package com.jozufozu.flywheel.backend.model;
import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
import com.jozufozu.flywheel.core.layout.BufferLayout;
public interface BufferedModel {
@ -10,11 +11,9 @@ public interface BufferedModel {
int getVertexCount();
/**
* The VBO/VAO should be bound externally.
* The VAO must be bound externally.
*/
void setupState();
void clearState();
void setupState(GlVertexArray vao);
void drawCall();
@ -27,7 +26,7 @@ public interface BufferedModel {
void delete();
default BufferLayout getFormat() {
default BufferLayout getLayout() {
return getType().getLayout();
}
@ -36,6 +35,6 @@ public interface BufferedModel {
}
default int getAttributeCount() {
return getFormat().getAttributeCount();
return getType().getLayout().getAttributeCount();
}
}

View file

@ -3,7 +3,14 @@ package com.jozufozu.flywheel.backend.model;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL31;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
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.Model;
/**
@ -11,26 +18,43 @@ import com.jozufozu.flywheel.core.model.Model;
*
* <br><em>This should be favored over a normal BufferedModel.</em>
*/
public class IndexedModel extends VBOModel {
public class IndexedModel implements BufferedModel {
protected final Model model;
protected final GlPrimitive primitiveMode;
protected ElementBuffer ebo;
protected GlBuffer vbo;
protected boolean deleted;
public IndexedModel(Model model) {
super(GlPrimitive.TRIANGLES, model);
this.model = model;
this.primitiveMode = GlPrimitive.TRIANGLES;
vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER);
vbo.bind();
// allocate the buffer on the gpu
vbo.ensureCapacity(model.size());
// mirror it in system memory, so we can write to it, and upload our model.
try (MappedBuffer buffer = vbo.getBuffer()) {
model.writeInto(buffer.unwrap());
} catch (Exception e) {
Flywheel.LOGGER.error(String.format("Error uploading model '%s':", model.name()), e);
}
vbo.unbind();
this.ebo = model.createEBO();
}
@Override
public void setupState() {
super.setupState();
ebo.bind();
}
@Override
public void clearState() {
super.clearState();
ebo.unbind();
/**
* The VBO/VAO should be bound externally.
*/
public void setupState(GlVertexArray vao) {
vbo.bind();
vao.enableArrays(getAttributeCount());
vao.bindAttributes(0, getType().getLayout());
}
@Override
@ -39,6 +63,9 @@ public class IndexedModel extends VBOModel {
GL20.glDrawElements(primitiveMode.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0);
}
/**
* Draws many instances of this model, assuming the appropriate state is already bound.
*/
@Override
public void drawInstances(int instanceCount) {
if (!valid()) return;
@ -47,4 +74,24 @@ public class IndexedModel extends VBOModel {
GL31.glDrawElementsInstanced(primitiveMode.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0, instanceCount);
}
public boolean isDeleted() {
return deleted;
}
@Override
public VertexType getType() {
return model.getType();
}
public int getVertexCount() {
return model.vertexCount();
}
public void delete() {
if (deleted) return;
deleted = true;
vbo.delete();
}
}

View file

@ -6,15 +6,15 @@ import java.util.List;
import org.lwjgl.opengl.GL32;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.api.vertex.VertexWriter;
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
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.Model;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.api.vertex.VertexWriter;
import com.jozufozu.flywheel.util.AttribUtil;
public class ModelPool implements ModelAllocator {
@ -178,18 +178,10 @@ public class ModelPool implements ModelAllocator {
}
@Override
public void setupState() {
public void setupState(GlVertexArray vao) {
vbo.bind();
ebo.bind();
AttribUtil.enableArrays(getAttributeCount());
ModelPool.this.vertexType.getLayout().vertexAttribPointers(0);
}
@Override
public void clearState() {
AttribUtil.disableArrays(getAttributeCount());
ebo.unbind();
vbo.unbind();
vao.enableArrays(getAttributeCount());
vao.bindAttributes(0, vertexType.getLayout());
}
@Override

View file

@ -1,47 +0,0 @@
package com.jozufozu.flywheel.backend.model;
import java.util.function.Supplier;
import com.jozufozu.flywheel.core.model.Model;
public class ModelRenderer {
protected Supplier<Model> modelSupplier;
protected BufferedModel model;
protected boolean initialized;
public ModelRenderer(Supplier<Model> modelSupplier) {
this.modelSupplier = modelSupplier;
}
/**
* Renders this model, checking first if there is anything to render.
*/
public void draw() {
if (!initialized) init();
if (!isValid()) return;
model.setupState();
model.drawCall();
model.clearState();
}
public void delete() {
if (model != null)
model.delete();
}
protected void init() {
initialized = true;
Model model = modelSupplier.get();
if (model.empty()) return;
this.model = new IndexedModel(model);
}
protected boolean isValid() {
return model != null && model.valid();
}
}

View file

@ -5,14 +5,14 @@ import static org.lwjgl.opengl.GL11.glDrawArrays;
import org.lwjgl.opengl.GL31;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
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.Model;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.util.AttribUtil;
public class VBOModel implements BufferedModel {
@ -57,15 +57,10 @@ public class VBOModel implements BufferedModel {
/**
* The VBO/VAO should be bound externally.
*/
public void setupState() {
public void setupState(GlVertexArray vao) {
vbo.bind();
AttribUtil.enableArrays(getAttributeCount());
getFormat().vertexAttribPointers(0);
}
public void clearState() {
AttribUtil.disableArrays(getAttributeCount());
vbo.unbind();
vao.enableArrays(getAttributeCount());
vao.bindAttributes(0, getLayout());
}
public void drawCall() {

View file

@ -9,7 +9,7 @@ import com.jozufozu.flywheel.api.vertex.VertexType;
* Classic Vertex Format struct with a clever name.
*
* <p>
* Used for vertices and instance. Describes the layout of a datatype in a buffer object.
* Used for vertices and instances. Describes the layout of a datatype in a buffer object.
* </p>
*
* @see com.jozufozu.flywheel.api.struct.StructType
@ -34,6 +34,10 @@ public class BufferLayout {
this.stride = stride;
}
public List<LayoutItem> getLayoutItems() {
return allAttributes;
}
public int getAttributeCount() {
return numAttributes;
}
@ -42,15 +46,6 @@ public class BufferLayout {
return stride;
}
public void vertexAttribPointers(int index) {
int offset = 0;
for (LayoutItem spec : this.allAttributes) {
spec.vertexAttribPointer(stride, index, offset);
index += spec.getAttributeCount();
offset += spec.getSize();
}
}
public static Builder builder() {
return new Builder();
}

View file

@ -1,27 +0,0 @@
package com.jozufozu.flywheel.util;
import org.lwjgl.opengl.GL20;
// TODO: move this functionality into GlVertexArray and track it
public class AttribUtil {
public static void enableArrays(int count) {
enableArrays(0, count);
}
public static void enableArrays(int fromInclusive, int toExclusive) {
for (int i = fromInclusive; i < toExclusive; i++) {
GL20.glEnableVertexAttribArray(i);
}
}
public static void disableArrays(int count) {
disableArrays(0, count);
}
public static void disableArrays(int fromInclusive, int toExclusive) {
for (int i = fromInclusive; i < toExclusive; i++) {
GL20.glDisableVertexAttribArray(i);
}
}
}