AMD driver workaround

- Just don't pool models
This commit is contained in:
Jozufozu 2021-12-13 19:55:50 -08:00
parent d094595f2e
commit d9fd668bbb
7 changed files with 103 additions and 76 deletions

View file

@ -9,6 +9,8 @@ import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import net.minecraft.Util;
/**
* An instance of this class stores information about what OpenGL features are available.
* <br>
@ -19,13 +21,27 @@ public class GlCompat {
public final InstancedArrays instancedArrays;
public final BufferStorage bufferStorage;
public final boolean amd;
public GlCompat(GLCapabilities caps) {
instancedArrays = getLatest(InstancedArrays.class, caps);
bufferStorage = getLatest(BufferStorage.class, caps);
if (Util.getPlatform() == Util.OS.WINDOWS) {
String vendor = GL20C.glGetString(GL20C.GL_VENDOR);
// vendor string I got was "ATI Technologies Inc."
amd = vendor.contains("ATI") || vendor.contains("AMD");
} else {
amd = false;
}
}
public boolean instancedArraysSupported() {
public boolean onAMDWindows() {
return amd;
}
public boolean instancedArraysSupported() {
return instancedArrays != InstancedArrays.UNSUPPORTED;
}

View file

@ -77,7 +77,7 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
model = modelAllocator.alloc(modelData, arenaModel -> {
vao.bind();
model.setupState();
arenaModel.setupState();
});
vao.bind();

View file

@ -5,10 +5,13 @@ import java.util.function.Supplier;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.RenderWork;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.Instancer;
import com.jozufozu.flywheel.api.Material;
import com.jozufozu.flywheel.backend.model.ImmediateAllocator;
import com.jozufozu.flywheel.backend.model.ModelAllocator;
import com.jozufozu.flywheel.backend.model.ModelPool;
import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.core.Formats;
@ -20,14 +23,18 @@ import com.jozufozu.flywheel.core.model.Model;
*/
public class InstancedMaterial<D extends InstanceData> implements Material<D> {
final ModelPool modelPool;
final ModelAllocator allocator;
protected final Cache<Object, GPUInstancer<D>> models;
protected final StructType<D> type;
public InstancedMaterial(StructType<D> spec) {
this.type = spec;
modelPool = new ModelPool(Formats.UNLIT_MODEL, 64);
if (Backend.getInstance().compat.onAMDWindows()) {
allocator = ImmediateAllocator.INSTANCE;
} else {
allocator = new ModelPool(Formats.UNLIT_MODEL, 64);
}
this.models = CacheBuilder.newBuilder()
.removalListener(notification -> {
GPUInstancer<?> instancer = (GPUInstancer<?>) notification.getValue();
@ -46,7 +53,7 @@ public class InstancedMaterial<D extends InstanceData> implements Material<D> {
@Override
public Instancer<D> model(Object key, Supplier<Model> modelSupplier) {
try {
return models.get(key, () -> new GPUInstancer<>(type, modelSupplier.get(), modelPool));
return models.get(key, () -> new GPUInstancer<>(type, modelSupplier.get(), allocator));
} catch (ExecutionException e) {
throw new RuntimeException("error creating instancer", e);
}
@ -61,7 +68,7 @@ public class InstancedMaterial<D extends InstanceData> implements Material<D> {
public void delete() {
models.invalidateAll();
modelPool.delete();
if (allocator instanceof ModelPool pool) pool.delete();
}
/**

View file

@ -4,6 +4,7 @@ import java.util.Collection;
import java.util.function.Consumer;
import java.util.function.Supplier;
import com.jozufozu.flywheel.backend.model.ModelPool;
import com.jozufozu.flywheel.core.shader.WorldProgram;
import com.mojang.math.Matrix4f;
@ -28,8 +29,10 @@ public class InstancedMaterialRenderer<P extends WorldProgram> {
// initialize all uninitialized instancers...
instancers.forEach(GPUInstancer::init);
// ...and then flush the model arena in case anything was marked for upload
material.modelPool.flush();
if (material.allocator instanceof ModelPool pool) {
// ...and then flush the model arena in case anything was marked for upload
pool.flush();
}
P program = this.program.get();

View file

@ -43,6 +43,8 @@ public class IndexedModel extends BufferedModel {
public void drawInstances(int instanceCount) {
if (!valid()) return;
ebo.bind();
GL31.glDrawElementsInstanced(primitiveMode.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0, instanceCount);
}
}

View file

@ -120,9 +120,12 @@ public class ModelPool implements ModelAllocator {
VecBufferWriter consumer = new VecBufferWriter(buffer);
int vertices = 0;
for (PooledModel model : models) {
model.first = vertices;
model.model.buffer(consumer);
if (model.callback != null) model.callback.onAlloc(model);
vertices += model.getVertexCount();
}
} catch (Exception e) {

View file

@ -125,80 +125,76 @@ public class ChestInstance<T extends BlockEntity & LidBlockEntity> extends TileE
private ModelPart getBaseModel() {
switch (chestType) {
case LEFT:
return ModelPart.builder("chest_base_left", 64, 64)
.sprite(renderMaterial.sprite())
.cuboid()
.textureOffset(0, 19)
.start(0, 0, 1)
.size(15, 10, 14)
.endCuboid()
.build();
case RIGHT:
return ModelPart.builder("chest_base_right", 64, 64)
.sprite(renderMaterial.sprite())
.cuboid()
.textureOffset(0, 19)
.start(1, 0, 1)
.size(15, 10, 14)
.endCuboid()
.build();
}
return switch (chestType) {
case LEFT -> ModelPart.builder("chest_base_left", 64, 64)
.sprite(renderMaterial.sprite())
.cuboid()
.textureOffset(0, 19)
.start(0, 0, 1)
.size(15, 10, 14)
.endCuboid()
.build();
case RIGHT -> ModelPart.builder("chest_base_right", 64, 64)
.sprite(renderMaterial.sprite())
.cuboid()
.textureOffset(0, 19)
.start(1, 0, 1)
.size(15, 10, 14)
.endCuboid()
.build();
default -> ModelPart.builder("chest_base", 64, 64)
.sprite(renderMaterial.sprite())
.cuboid()
.textureOffset(0, 19)
.start(1, 0, 1)
.end(15, 10, 15)
.endCuboid()
.build();
};
return ModelPart.builder("chest_base", 64, 64)
.sprite(renderMaterial.sprite())
.cuboid()
.textureOffset(0, 19)
.start(1, 0, 1)
.end(15, 10, 15)
.endCuboid()
.build();
}
private ModelPart getLidModel() {
switch (chestType) {
case LEFT:
return ModelPart.builder("chest_lid_left", 64, 64)
.sprite(renderMaterial.sprite())
.cuboid()
.textureOffset(0, 0)
.start(0, 0, 1)
.size(15, 5, 14)
.endCuboid()
.cuboid()
.start(0, -2, 15)
.size(1, 4, 1)
.endCuboid()
.build();
case RIGHT:
return ModelPart.builder("chest_lid_right", 64, 64)
.sprite(renderMaterial.sprite())
.cuboid()
.textureOffset(0, 0)
.start(1, 0, 1)
.size(15, 5, 14)
.endCuboid()
.cuboid()
.start(15, -2, 15)
.size(1, 4, 1)
.endCuboid()
.build();
}
return switch (chestType) {
case LEFT -> ModelPart.builder("chest_lid_left", 64, 64)
.sprite(renderMaterial.sprite())
.cuboid()
.textureOffset(0, 0)
.start(0, 0, 1)
.size(15, 5, 14)
.endCuboid()
.cuboid()
.start(0, -2, 15)
.size(1, 4, 1)
.endCuboid()
.build();
case RIGHT -> ModelPart.builder("chest_lid_right", 64, 64)
.sprite(renderMaterial.sprite())
.cuboid()
.textureOffset(0, 0)
.start(1, 0, 1)
.size(15, 5, 14)
.endCuboid()
.cuboid()
.start(15, -2, 15)
.size(1, 4, 1)
.endCuboid()
.build();
default -> ModelPart.builder("chest_lid", 64, 64)
.sprite(renderMaterial.sprite())
.cuboid()
.textureOffset(0, 0)
.start(1, 0, 1)
.size(14, 5, 14)
.endCuboid()
.cuboid()
.start(7, -2, 15)
.size(2, 4, 1)
.endCuboid()
.build();
};
return ModelPart.builder("chest_lid", 64, 64)
.sprite(renderMaterial.sprite())
.cuboid()
.textureOffset(0, 0)
.start(1, 0, 1)
.size(14, 5, 14)
.endCuboid()
.cuboid()
.start(7, -2, 15)
.size(2, 4, 1)
.endCuboid()
.build();
}
public static boolean isChristmas() {