Contraptions and engines

- Sort of get the batching engine working for contraptions but this feels wrong
 - TaskEngine gets passed in methods
 - Better naming for TaskEngines
 - Do BufferSource ourselves
 - Change BufferBuilderMixin to allow for injection into BufferBuilder objects
This commit is contained in:
Jozufozu 2021-12-23 14:41:10 -08:00
parent 5cca71332d
commit 4d5391f5dc
19 changed files with 197 additions and 150 deletions

View file

@ -115,4 +115,9 @@ public abstract class AbstractInstancer<D extends InstanceData> implements Insta
return instanceData;
}
@Override
public String toString() {
return "Instancer[" + modelData + ']';
}
}

View file

@ -32,13 +32,11 @@ public abstract class InstanceManager<T> implements InstancingEngine.OriginShift
protected final Map<T, AbstractInstance> instances;
protected final Object2ObjectOpenHashMap<T, ITickableInstance> tickableInstances;
protected final Object2ObjectOpenHashMap<T, IDynamicInstance> dynamicInstances;
private final TaskEngine taskEngine;
protected int frame;
protected int tick;
public InstanceManager(TaskEngine taskEngine, MaterialManager materialManager) {
this.taskEngine = taskEngine;
public InstanceManager(MaterialManager materialManager) {
this.materialManager = materialManager;
this.queuedUpdates = new HashSet<>(64);
this.queuedAdditions = new HashSet<>(64);
@ -78,7 +76,7 @@ public abstract class InstanceManager<T> implements InstancingEngine.OriginShift
* Queued updates are processed.
* </p>
*/
public void tick(double cameraX, double cameraY, double cameraZ) {
public void tick(TaskEngine taskEngine, double cameraX, double cameraY, double cameraZ) {
tick++;
processQueuedUpdates();
@ -120,7 +118,7 @@ public abstract class InstanceManager<T> implements InstancingEngine.OriginShift
if ((tick % getUpdateDivisor(dX, dY, dZ)) == 0) instance.tick();
}
public void beginFrame(Camera info) {
public void beginFrame(TaskEngine taskEngine, Camera info) {
frame++;
processQueuedAdditions();

View file

@ -16,6 +16,8 @@ import com.jozufozu.flywheel.event.RenderLayerEvent;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.entity.BlockEntity;
/**
@ -29,11 +31,12 @@ public class InstanceWorld {
protected final InstanceManager<Entity> entityInstanceManager;
protected final InstanceManager<BlockEntity> tileEntityInstanceManager;
protected final BatchExecutor taskEngine;
protected final ParallelTaskEngine taskEngine;
public InstanceWorld() {
public InstanceWorld(LevelAccessor levelAccessor) {
Level world = (Level) levelAccessor;
this.taskEngine = new BatchExecutor();
this.taskEngine = new ParallelTaskEngine("Flywheel " + world.dimension().location());
this.taskEngine.startWorkers();
FlwEngine engine = Backend.getInstance()
@ -42,19 +45,19 @@ public class InstanceWorld {
switch (engine) {
case INSTANCING -> {
InstancingEngine<WorldProgram> manager = InstancingEngine.builder(Contexts.WORLD)
.build(this.taskEngine);
.build();
entityInstanceManager = new EntityInstanceManager(this.taskEngine, manager);
tileEntityInstanceManager = new TileInstanceManager(this.taskEngine, manager);
entityInstanceManager = new EntityInstanceManager(manager);
tileEntityInstanceManager = new TileInstanceManager(manager);
manager.addListener(entityInstanceManager);
manager.addListener(tileEntityInstanceManager);
this.engine = manager;
}
case BATCHING -> {
this.engine = new BatchingEngine(this.taskEngine);
entityInstanceManager = new EntityInstanceManager(this.taskEngine, this.engine);
tileEntityInstanceManager = new TileInstanceManager(this.taskEngine, this.engine);
this.engine = new BatchingEngine();
entityInstanceManager = new EntityInstanceManager(this.engine);
tileEntityInstanceManager = new TileInstanceManager(this.engine);
}
default -> throw new IllegalArgumentException("Unknown engine type");
}
@ -91,8 +94,8 @@ public class InstanceWorld {
taskEngine.syncPoint();
tileEntityInstanceManager.beginFrame(event.getInfo());
entityInstanceManager.beginFrame(event.getInfo());
tileEntityInstanceManager.beginFrame(taskEngine, event.getInfo());
entityInstanceManager.beginFrame(taskEngine, event.getInfo());
}
/**
@ -107,8 +110,8 @@ public class InstanceWorld {
if (renderViewEntity == null) return;
tileEntityInstanceManager.tick(renderViewEntity.getX(), renderViewEntity.getY(), renderViewEntity.getZ());
entityInstanceManager.tick(renderViewEntity.getX(), renderViewEntity.getY(), renderViewEntity.getZ());
tileEntityInstanceManager.tick(taskEngine, renderViewEntity.getX(), renderViewEntity.getY(), renderViewEntity.getZ());
entityInstanceManager.tick(taskEngine, renderViewEntity.getX(), renderViewEntity.getY(), renderViewEntity.getZ());
}
/**
@ -116,7 +119,10 @@ public class InstanceWorld {
*/
public void renderLayer(RenderLayerEvent event) {
taskEngine.syncPoint();
engine.render(event);
event.stack.pushPose();
event.stack.translate(-event.camX, -event.camY, -event.camZ);
engine.render(taskEngine, event);
event.stack.popPose();
}
/**

View file

@ -22,7 +22,7 @@ import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber(Dist.CLIENT)
public class InstancedRenderDispatcher {
private static final WorldAttached<InstanceWorld> instanceWorlds = new WorldAttached<>($ -> new InstanceWorld());
private static final WorldAttached<InstanceWorld> instanceWorlds = new WorldAttached<>(InstanceWorld::new);
/**
* Call this when you want to manually run {@link AbstractInstance#update()}.

View file

@ -17,7 +17,7 @@ import com.jozufozu.flywheel.backend.instancing.batching.WaitGroup;
import net.minecraft.util.Mth;
// https://github.com/CaffeineMC/sodium-fabric/blob/5d364ed5ba63f9067fcf72a078ca310bff4db3e9/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java
public class BatchExecutor implements TaskEngine {
public class ParallelTaskEngine implements TaskEngine {
private static final Logger LOGGER = LogManager.getLogger("BatchExecutor");
private final AtomicBoolean running = new AtomicBoolean(false);
@ -30,7 +30,10 @@ public class BatchExecutor implements TaskEngine {
private final int threadCount;
public BatchExecutor() {
private final String name;
public ParallelTaskEngine(String name) {
this.name = name;
threadCount = getOptimalThreadCount();
}
@ -49,7 +52,7 @@ public class BatchExecutor implements TaskEngine {
for (int i = 0; i < this.threadCount; i++) {
Thread thread = new Thread(new WorkerRunnable(), "Engine Executor " + i);
Thread thread = new Thread(new WorkerRunnable(), name + " " + i);
thread.setPriority(Math.max(0, Thread.NORM_PRIORITY - 2));
thread.start();
@ -121,9 +124,9 @@ public class BatchExecutor implements TaskEngine {
Runnable job = this.jobQueue.pollFirst();
if (job == null) {
synchronized (BatchExecutor.this.jobNotifier) {
synchronized (ParallelTaskEngine.this.jobNotifier) {
try {
BatchExecutor.this.jobNotifier.wait();
ParallelTaskEngine.this.jobNotifier.wait();
} catch (InterruptedException ignored) {
}
}
@ -138,7 +141,7 @@ public class BatchExecutor implements TaskEngine {
} catch (Exception e) {
Flywheel.log.error(e);
} finally {
BatchExecutor.this.wg.done();
ParallelTaskEngine.this.wg.done();
}
}
@ -155,19 +158,19 @@ public class BatchExecutor implements TaskEngine {
}
private class WorkerRunnable implements Runnable {
private final AtomicBoolean running = BatchExecutor.this.running;
private final AtomicBoolean running = ParallelTaskEngine.this.running;
@Override
public void run() {
// Run until the chunk builder shuts down
while (this.running.get()) {
Runnable job = BatchExecutor.this.getNextTask();
Runnable job = ParallelTaskEngine.this.getNextTask();
if (job == null) {
continue;
}
BatchExecutor.this.processTask(job);
ParallelTaskEngine.this.processTask(job);
}
}

View file

@ -3,15 +3,15 @@ package com.jozufozu.flywheel.backend.instancing;
import com.jozufozu.flywheel.event.RenderLayerEvent;
import net.minecraft.client.Camera;
import net.minecraft.client.renderer.MultiBufferSource;
public interface RenderDispatcher {
/**
* Render every model for every material.
*
* @param event Context for rendering.
* @param taskEngine
* @param event Context for rendering.
*/
void render(RenderLayerEvent event);
void render(TaskEngine taskEngine, RenderLayerEvent event);
/**
* Maintain the integer origin coordinate to be within a certain distance from the camera in all directions.

View file

@ -2,11 +2,11 @@ package com.jozufozu.flywheel.backend.instancing;
import org.jetbrains.annotations.NotNull;
public class ImmediateExecutor implements TaskEngine {
public class SerialTaskEngine implements TaskEngine {
public static final ImmediateExecutor INSTANCE = new ImmediateExecutor();
public static final SerialTaskEngine INSTANCE = new SerialTaskEngine();
private ImmediateExecutor() {
private SerialTaskEngine() {
}
@Override

View file

@ -0,0 +1,79 @@
package com.jozufozu.flywheel.backend.instancing;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import com.jozufozu.flywheel.backend.model.BufferBuilderHack;
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
import com.mojang.blaze3d.platform.MemoryTracker;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.renderer.RenderType;
public class SuperBufferSource {
protected final Map<RenderType, DrawBuffer> buffers = new HashMap<>();
private final BufferBuilder scratch;
public SuperBufferSource() {
scratch = new BufferBuilder(8);
((BufferBuilderHack) scratch).freeBuffer();
}
public DirectVertexConsumer getBuffer(RenderType renderType, int vertexCount) {
return buffers.computeIfAbsent(renderType, DrawBuffer::new)
.begin(vertexCount);
}
public void endBatch() {
// TODO: when/if this causes trouble with shaders, try to inject our BufferBuilders
// into the RenderBuffers from context.
BufferBuilderHack hack = (BufferBuilderHack) scratch;
for (Map.Entry<RenderType, DrawBuffer> entry : buffers.entrySet()) {
DrawBuffer builder = entry.getValue();
if (builder.expectedVertices > 0) {
RenderType type = entry.getKey();
hack.hackBegin(builder.backingBuffer, type.format(), builder.expectedVertices);
type.end(scratch, 0, 0, 0);
builder.expectedVertices = 0;
}
}
}
private static class DrawBuffer {
private final RenderType type;
private ByteBuffer backingBuffer;
private int expectedVertices;
public DrawBuffer(RenderType type) {
this.type = type;
}
public DirectVertexConsumer begin(int vertexCount) {
this.expectedVertices = vertexCount;
VertexFormat format = type.format();
int byteSize = format.getVertexSize() * vertexCount;
if (backingBuffer == null) {
backingBuffer = MemoryTracker.create(byteSize);
} if (byteSize > backingBuffer.capacity()) {
backingBuffer = MemoryTracker.resize(backingBuffer, byteSize);
}
return new DirectVertexConsumer(backingBuffer, format, vertexCount);
}
}
}

View file

@ -7,13 +7,11 @@ import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.MaterialGroup;
import com.jozufozu.flywheel.api.struct.Batched;
import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.backend.instancing.SuperBufferSource;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.backend.model.DirectBufferBuilder;
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
public class BatchedMaterialGroup implements MaterialGroup {
@ -36,17 +34,8 @@ public class BatchedMaterialGroup implements MaterialGroup {
}
}
public void render(PoseStack stack, MultiBufferSource source, TaskEngine pool) {
VertexConsumer buffer = source.getBuffer(state);
public void render(PoseStack stack, SuperBufferSource source, TaskEngine pool) {
if (buffer instanceof DirectBufferBuilder direct) {
renderParallel(stack, pool, direct);
} else {
renderSerial(stack, buffer);
}
}
private void renderParallel(PoseStack stack, TaskEngine pool, DirectBufferBuilder direct) {
int vertexCount = 0;
for (BatchedMaterial<?> material : materials.values()) {
for (CPUInstancer<?> instancer : material.models.values()) {
@ -55,7 +44,7 @@ public class BatchedMaterialGroup implements MaterialGroup {
}
}
DirectVertexConsumer consumer = direct.intoDirectConsumer(vertexCount);
DirectVertexConsumer consumer = source.getBuffer(state, vertexCount);
// avoids rendering garbage, but doesn't fix the issue of some instances not being buffered
consumer.memSetZero();
@ -74,12 +63,6 @@ public class BatchedMaterialGroup implements MaterialGroup {
}
}
private void renderSerial(PoseStack stack, VertexConsumer consumer) {
for (BatchedMaterial<?> value : materials.values()) {
value.setupAndRenderInto(stack, consumer);
}
}
public void clear() {
materials.values().forEach(BatchedMaterial::clear);
}

View file

@ -6,6 +6,7 @@ import java.util.Map;
import com.jozufozu.flywheel.api.MaterialGroup;
import com.jozufozu.flywheel.backend.RenderLayer;
import com.jozufozu.flywheel.backend.instancing.SuperBufferSource;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.backend.instancing.Engine;
import com.jozufozu.flywheel.event.RenderLayerEvent;
@ -21,19 +22,17 @@ import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
public class BatchingEngine implements Engine, MultiBufferSource {
public class BatchingEngine implements Engine {
protected final Map<RenderType, BufferBuilder> buffers = new HashMap<>();
protected final Map<RenderLayer, Map<RenderType, BatchedMaterialGroup>> layers;
protected final TaskEngine taskEngine;
private final Map<RenderLayer, Map<RenderType, BatchedMaterialGroup>> layers;
private final SuperBufferSource superBufferSource = new SuperBufferSource();
public BatchingEngine(TaskEngine taskEngine) {
public BatchingEngine() {
this.layers = new EnumMap<>(RenderLayer.class);
for (RenderLayer value : RenderLayer.values()) {
layers.put(value, new HashMap<>());
}
this.taskEngine = taskEngine;
}
@Override
@ -47,21 +46,15 @@ public class BatchingEngine implements Engine, MultiBufferSource {
}
@Override
public void render(RenderLayerEvent event) {
PoseStack stack = event.stack;
public void render(TaskEngine taskEngine, RenderLayerEvent event) {
stack.pushPose();
stack.translate(-event.camX, -event.camY, -event.camZ);
for (BatchedMaterialGroup group : layers.get(event.getLayer()).values()) {
group.render(stack, this, taskEngine);
Map<RenderType, BatchedMaterialGroup> groups = layers.get(event.getLayer());
for (BatchedMaterialGroup group : groups.values()) {
group.render(event.stack, superBufferSource, taskEngine);
}
taskEngine.syncPoint();
stack.popPose();
// FIXME: this probably breaks some vanilla stuff but it works much better for flywheel
Matrix4f mat = new Matrix4f();
mat.setIdentity();
@ -71,20 +64,7 @@ public class BatchingEngine implements Engine, MultiBufferSource {
Lighting.setupLevel(mat);
}
// TODO: when/if this causes trouble with shaders, try to inject our BufferBuilders
// into the RenderBuffers from context.
buffers.forEach((type, builder) -> type.end(builder, 0, 0, 0));
}
@Override
public VertexConsumer getBuffer(RenderType renderType) {
BufferBuilder builder = buffers.computeIfAbsent(renderType, type -> new BufferBuilder(type.bufferSize()));
if (!builder.building()) {
builder.begin(renderType.mode(), renderType.format());
}
return builder;
superBufferSource.endBatch();
}
@Override

View file

@ -3,7 +3,6 @@ package com.jozufozu.flywheel.backend.instancing.entity;
import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
import com.jozufozu.flywheel.backend.instancing.BatchExecutor;
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
@ -15,8 +14,8 @@ import net.minecraft.world.level.Level;
public class EntityInstanceManager extends InstanceManager<Entity> {
public EntityInstanceManager(TaskEngine executor, MaterialManager materialManager) {
super(executor, materialManager);
public EntityInstanceManager(MaterialManager materialManager) {
super(materialManager);
}
@Override

View file

@ -10,7 +10,6 @@ import javax.annotation.Nullable;
import com.jozufozu.flywheel.api.MaterialGroup;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.backend.instancing.ImmediateExecutor;
import com.jozufozu.flywheel.backend.RenderLayer;
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
@ -22,7 +21,6 @@ import com.jozufozu.flywheel.util.WeakHashSet;
import com.mojang.math.Matrix4f;
import net.minecraft.client.Camera;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
@ -35,7 +33,6 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
protected BlockPos originCoordinate = BlockPos.ZERO;
protected final TaskEngine taskEngine;
protected final WorldContext<P> context;
protected final GroupFactory<P> groupFactory;
protected final boolean ignoreOriginCoordinate;
@ -45,15 +42,14 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
private final WeakHashSet<OriginShiftListener> listeners;
public InstancingEngine(WorldContext<P> context, TaskEngine taskEngine) {
this(taskEngine, context, InstancedMaterialGroup::new, false);
this(context, InstancedMaterialGroup::new, false);
}
public static <P extends WorldProgram> Builder<P> builder(WorldContext<P> context) {
return new Builder<>(context);
}
public InstancingEngine(TaskEngine taskEngine, WorldContext<P> context, GroupFactory<P> groupFactory, boolean ignoreOriginCoordinate) {
this.taskEngine = taskEngine;
public InstancingEngine(WorldContext<P> context, GroupFactory<P> groupFactory, boolean ignoreOriginCoordinate) {
this.context = context;
this.ignoreOriginCoordinate = ignoreOriginCoordinate;
@ -82,7 +78,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
* Render every model for every material.
*/
@Override
public void render(RenderLayerEvent event) {
public void render(TaskEngine taskEngine, RenderLayerEvent event) {
double camX;
double camY;
double camZ;
@ -205,11 +201,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
}
public InstancingEngine<P> build() {
return build(ImmediateExecutor.INSTANCE);
}
public InstancingEngine<P> build(TaskEngine taskEngine) {
return new InstancingEngine<>(taskEngine, context, groupFactory, ignoreOriginCoordinate);
return new InstancingEngine<>(context, groupFactory, ignoreOriginCoordinate);
}
}
}

View file

@ -3,7 +3,6 @@ package com.jozufozu.flywheel.backend.instancing.tile;
import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
import com.jozufozu.flywheel.backend.instancing.BatchExecutor;
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
@ -15,8 +14,8 @@ import net.minecraft.world.level.block.entity.BlockEntity;
public class TileInstanceManager extends InstanceManager<BlockEntity> {
public TileInstanceManager(TaskEngine executor, MaterialManager materialManager) {
super(executor, materialManager);
public TileInstanceManager(MaterialManager materialManager) {
super(materialManager);
}
@Override

View file

@ -0,0 +1,16 @@
package com.jozufozu.flywheel.backend.model;
import java.nio.ByteBuffer;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.VertexFormat;
/**
* Duck interface used on {@link BufferBuilder} to provide lower level access to the backing memory.
*/
public interface BufferBuilderHack {
void freeBuffer();
void hackBegin(ByteBuffer buffer, VertexFormat format, int vertexCount);
}

View file

@ -1,20 +0,0 @@
package com.jozufozu.flywheel.backend.model;
import com.mojang.blaze3d.vertex.BufferBuilder;
/**
* Duck interface used on {@link BufferBuilder} to provide lower level access to the backing memory.
*/
public interface DirectBufferBuilder {
/**
* Create a DirectVertexConsumer from this BufferBuilder.
*
* <p>
* After this function returns, the internal state of the BufferBuilder will be as if
* {@link BufferBuilder#endVertex()} was called vertexCount times. It is up to the callee
* to actually populate the BufferBuilder with vertices using the returned value.
* </p>
*/
DirectVertexConsumer intoDirectConsumer(int vertexCount);
}

View file

@ -13,7 +13,7 @@ import com.mojang.blaze3d.vertex.VertexFormatElement;
/**
* An unsafe vertex consumer allowing for unchecked writes into a ByteBuffer.
*
* @see DirectBufferBuilder
* @see BufferBuilderHack
*/
public class DirectVertexConsumer implements VertexConsumer {
public final VertexFormat format;

View file

@ -1,7 +1,6 @@
package com.jozufozu.flywheel.core.crumbling;
import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.backend.instancing.ImmediateExecutor;
import com.jozufozu.flywheel.backend.instancing.tile.TileInstanceManager;
import net.minecraft.core.BlockPos;
@ -9,7 +8,7 @@ import net.minecraft.core.BlockPos;
public class CrumblingInstanceManager extends TileInstanceManager {
public CrumblingInstanceManager(MaterialManager materialManager) {
super(ImmediateExecutor.INSTANCE, materialManager);
super(materialManager);
}
@Override

View file

@ -6,6 +6,7 @@ import java.util.SortedSet;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
import com.jozufozu.flywheel.backend.instancing.SerialTaskEngine;
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
import com.jozufozu.flywheel.core.Contexts;
@ -74,9 +75,9 @@ public class CrumblingRenderer {
if (_currentLayer != null) {
stage.getValue().forEach(instanceManager::add);
instanceManager.beginFrame(info);
instanceManager.beginFrame(SerialTaskEngine.INSTANCE, info);
materials.render(event);
materials.render(SerialTaskEngine.INSTANCE, event);
instanceManager.invalidate();
}

View file

@ -5,29 +5,34 @@ import java.nio.ByteBuffer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.lwjgl.system.MemoryUtil;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import com.jozufozu.flywheel.backend.instancing.SuperBufferSource;
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
import com.jozufozu.flywheel.backend.model.DirectBufferBuilder;
import com.jozufozu.flywheel.backend.model.BufferBuilderHack;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.blaze3d.vertex.VertexFormatElement;
@Mixin(BufferBuilder.class)
public abstract class BufferBuilderMixin implements DirectBufferBuilder {
public abstract class BufferBuilderMixin implements BufferBuilderHack {
@Shadow
private ByteBuffer buffer;
@Shadow
private boolean building;
@Shadow
public abstract void begin(VertexFormat.Mode p_166780_, VertexFormat p_166781_);
@Shadow
private VertexFormat.Mode mode;
@Shadow
private VertexFormat format;
@Shadow
protected abstract void ensureCapacity(int p_85723_);
@Shadow
private int vertices;
@Shadow
@Nullable
private VertexFormatElement currentElement;
@ -36,24 +41,26 @@ public abstract class BufferBuilderMixin implements DirectBufferBuilder {
private int elementIndex;
@Shadow
private int nextElementByte;
private int vertices;
@Override
@Nonnull
public DirectVertexConsumer intoDirectConsumer(int vertexCount) {
int bytes = vertexCount * format.getVertexSize();
// ensure we have capacity for one extra vertex, BufferBuilder does this on #endVertex
ensureCapacity(bytes + format.getVertexSize());
public void freeBuffer() {
if (this.buffer != null) {
MemoryUtil.memFree(this.buffer);
this.buffer = null;
}
}
DirectVertexConsumer consumer = new DirectVertexConsumer(this.buffer, this.format, vertexCount);
@Override
public void hackBegin(@Nonnull ByteBuffer buffer, @Nonnull VertexFormat format, int vertexCount) {
this.building = true;
this.mode = VertexFormat.Mode.QUADS;
this.vertices += vertexCount;
this.currentElement = format.getElements()
.get(0);
this.buffer = buffer;
this.format = format;
this.vertices = vertexCount;
this.currentElement = this.format.getElements().get(0);
this.elementIndex = 0;
this.nextElementByte += bytes;
this.buffer.position(this.buffer.position() + bytes);
return consumer;
}
}