mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-28 16:06:28 +01:00
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:
parent
5cca71332d
commit
4d5391f5dc
19 changed files with 197 additions and 150 deletions
|
@ -115,4 +115,9 @@ public abstract class AbstractInstancer<D extends InstanceData> implements Insta
|
|||
|
||||
return instanceData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Instancer[" + modelData + ']';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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()}.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue