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.MemoryStack;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import net.minecraft.Util;
/** /**
* An instance of this class stores information about what OpenGL features are available. * An instance of this class stores information about what OpenGL features are available.
* <br> * <br>
@ -19,13 +21,27 @@ public class GlCompat {
public final InstancedArrays instancedArrays; public final InstancedArrays instancedArrays;
public final BufferStorage bufferStorage; public final BufferStorage bufferStorage;
public final boolean amd;
public GlCompat(GLCapabilities caps) { public GlCompat(GLCapabilities caps) {
instancedArrays = getLatest(InstancedArrays.class, caps); instancedArrays = getLatest(InstancedArrays.class, caps);
bufferStorage = getLatest(BufferStorage.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; return instancedArrays != InstancedArrays.UNSUPPORTED;
} }

View file

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

View file

@ -5,10 +5,13 @@ import java.util.function.Supplier;
import com.google.common.cache.Cache; import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.RenderWork; import com.jozufozu.flywheel.backend.RenderWork;
import com.jozufozu.flywheel.api.InstanceData; import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.Instancer; import com.jozufozu.flywheel.api.Instancer;
import com.jozufozu.flywheel.api.Material; 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.backend.model.ModelPool;
import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.core.Formats; 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> { public class InstancedMaterial<D extends InstanceData> implements Material<D> {
final ModelPool modelPool; final ModelAllocator allocator;
protected final Cache<Object, GPUInstancer<D>> models; protected final Cache<Object, GPUInstancer<D>> models;
protected final StructType<D> type; protected final StructType<D> type;
public InstancedMaterial(StructType<D> spec) { public InstancedMaterial(StructType<D> spec) {
this.type = 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() this.models = CacheBuilder.newBuilder()
.removalListener(notification -> { .removalListener(notification -> {
GPUInstancer<?> instancer = (GPUInstancer<?>) notification.getValue(); GPUInstancer<?> instancer = (GPUInstancer<?>) notification.getValue();
@ -46,7 +53,7 @@ public class InstancedMaterial<D extends InstanceData> implements Material<D> {
@Override @Override
public Instancer<D> model(Object key, Supplier<Model> modelSupplier) { public Instancer<D> model(Object key, Supplier<Model> modelSupplier) {
try { try {
return models.get(key, () -> new GPUInstancer<>(type, modelSupplier.get(), modelPool)); return models.get(key, () -> new GPUInstancer<>(type, modelSupplier.get(), allocator));
} catch (ExecutionException e) { } catch (ExecutionException e) {
throw new RuntimeException("error creating instancer", e); throw new RuntimeException("error creating instancer", e);
} }
@ -61,7 +68,7 @@ public class InstancedMaterial<D extends InstanceData> implements Material<D> {
public void delete() { public void delete() {
models.invalidateAll(); 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.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.jozufozu.flywheel.backend.model.ModelPool;
import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.core.shader.WorldProgram;
import com.mojang.math.Matrix4f; import com.mojang.math.Matrix4f;
@ -28,8 +29,10 @@ public class InstancedMaterialRenderer<P extends WorldProgram> {
// initialize all uninitialized instancers... // initialize all uninitialized instancers...
instancers.forEach(GPUInstancer::init); instancers.forEach(GPUInstancer::init);
// ...and then flush the model arena in case anything was marked for upload if (material.allocator instanceof ModelPool pool) {
material.modelPool.flush(); // ...and then flush the model arena in case anything was marked for upload
pool.flush();
}
P program = this.program.get(); P program = this.program.get();

View file

@ -43,6 +43,8 @@ public class IndexedModel extends BufferedModel {
public void drawInstances(int instanceCount) { public void drawInstances(int instanceCount) {
if (!valid()) return; if (!valid()) return;
ebo.bind();
GL31.glDrawElementsInstanced(primitiveMode.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0, instanceCount); 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); VecBufferWriter consumer = new VecBufferWriter(buffer);
int vertices = 0;
for (PooledModel model : models) { for (PooledModel model : models) {
model.first = vertices;
model.model.buffer(consumer); model.model.buffer(consumer);
if (model.callback != null) model.callback.onAlloc(model); if (model.callback != null) model.callback.onAlloc(model);
vertices += model.getVertexCount();
} }
} catch (Exception e) { } catch (Exception e) {

View file

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