mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-07 12:56:31 +01:00
Batched simplification
- Perform various cleanup in batching code - Remove ClientLevel argument from InstanceVertexTransformer#transform - Rename Plan#maybeSimplify to simplify - Rename some classes - Move TickContext from impl to impl.visualization - Move VertexListProviderRegistryImpl from impl to impl.vertex
This commit is contained in:
parent
afb14bc1f6
commit
961fafce0d
33 changed files with 172 additions and 169 deletions
|
@ -12,6 +12,7 @@ import net.minecraft.client.Camera;
|
||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
|
|
||||||
public interface Engine extends InstancerProvider {
|
public interface Engine extends InstancerProvider {
|
||||||
|
Plan<RenderContext> createFramePlan();
|
||||||
|
|
||||||
void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage);
|
void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage);
|
||||||
|
|
||||||
|
@ -28,6 +29,4 @@ public interface Engine extends InstancerProvider {
|
||||||
void addDebugInfo(List<String> info);
|
void addDebugInfo(List<String> info);
|
||||||
|
|
||||||
void delete();
|
void delete();
|
||||||
|
|
||||||
Plan<RenderContext> createFramePlan();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@ package com.jozufozu.flywheel.api.instance;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.vertex.MutableVertexList;
|
import com.jozufozu.flywheel.api.vertex.MutableVertexList;
|
||||||
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
|
||||||
|
|
||||||
public interface InstanceVertexTransformer<I extends Instance> {
|
public interface InstanceVertexTransformer<I extends Instance> {
|
||||||
void transform(MutableVertexList vertexList, I instance, ClientLevel level);
|
void transform(MutableVertexList vertexList, I instance);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,5 +67,5 @@ public interface Plan<C> {
|
||||||
*
|
*
|
||||||
* @return A simplified plan, or this.
|
* @return A simplified plan, or this.
|
||||||
*/
|
*/
|
||||||
Plan<C> maybeSimplify();
|
Plan<C> simplify();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package com.jozufozu.flywheel.api.vertex;
|
package com.jozufozu.flywheel.api.vertex;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.impl.VertexListProviderRegistryImpl;
|
import com.jozufozu.flywheel.impl.vertex.VertexListProviderRegistryImpl;
|
||||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
|
||||||
public final class VertexListProviderRegistry {
|
public final class VertexListProviderRegistry {
|
||||||
|
|
|
@ -20,5 +20,5 @@ public interface DynamicVisual extends Visual {
|
||||||
* <p>
|
* <p>
|
||||||
* {@link Instancer}/{@link Instance} creation/acquisition is safe here.
|
* {@link Instancer}/{@link Instance} creation/acquisition is safe here.
|
||||||
*/
|
*/
|
||||||
void beginFrame(VisualFrameContext context);
|
void beginFrame(VisualFrameContext ctx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,5 +27,5 @@ public interface TickableVisual extends Visual {
|
||||||
* <p>
|
* <p>
|
||||||
* {@link Instancer}/{@link Instance} creation/acquisition is safe here.
|
* {@link Instancer}/{@link Instance} creation/acquisition is safe here.
|
||||||
*/
|
*/
|
||||||
void tick(VisualTickContext c);
|
void tick(VisualTickContext ctx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
public record BatchContext(ClientLevel level, PoseStack.Pose matrices, FrustumIntersection frustum) {
|
public record BatchContext(FrustumIntersection frustum, ClientLevel level, PoseStack.Pose matrices) {
|
||||||
@NotNull
|
@NotNull
|
||||||
static BatchContext create(RenderContext context, BlockPos origin) {
|
static BatchContext create(RenderContext context, BlockPos origin) {
|
||||||
Vec3 cameraPos = context.camera()
|
Vec3 cameraPos = context.camera()
|
||||||
|
@ -23,6 +23,6 @@ public record BatchContext(ClientLevel level, PoseStack.Pose matrices, FrustumIn
|
||||||
org.joml.Matrix4f proj = MatrixUtil.toJoml(context.viewProjection());
|
org.joml.Matrix4f proj = MatrixUtil.toJoml(context.viewProjection());
|
||||||
proj.translate((float) (origin.getX() - cameraPos.x), (float) (origin.getY() - cameraPos.y), (float) (origin.getZ() - cameraPos.z));
|
proj.translate((float) (origin.getX() - cameraPos.x), (float) (origin.getY() - cameraPos.y), (float) (origin.getZ() - cameraPos.z));
|
||||||
|
|
||||||
return new BatchContext(context.level(), stack.last(), new FrustumIntersection(proj));
|
return new BatchContext(new FrustumIntersection(proj), context.level(), stack.last());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,9 @@ import java.util.Set;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||||
import com.jozufozu.flywheel.extension.BufferBuilderExtension;
|
import com.jozufozu.flywheel.extension.BufferBuilderExtension;
|
||||||
import com.jozufozu.flywheel.extension.RenderTypeExtension;
|
|
||||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
public class BatchedDrawTracker {
|
||||||
|
|
||||||
public class BatchingDrawTracker {
|
|
||||||
private final Map<RenderStage, Set<DrawBuffer>> activeBuffers = new EnumMap<>(RenderStage.class);
|
private final Map<RenderStage, Set<DrawBuffer>> activeBuffers = new EnumMap<>(RenderStage.class);
|
||||||
{
|
{
|
||||||
for (RenderStage stage : RenderStage.values()) {
|
for (RenderStage stage : RenderStage.values()) {
|
||||||
|
@ -22,31 +19,33 @@ public class BatchingDrawTracker {
|
||||||
|
|
||||||
private final BufferBuilder scratch;
|
private final BufferBuilder scratch;
|
||||||
|
|
||||||
public BatchingDrawTracker() {
|
public BatchedDrawTracker() {
|
||||||
scratch = new BufferBuilder(8);
|
scratch = new BufferBuilder(8);
|
||||||
|
|
||||||
((BufferBuilderExtension) scratch).flywheel$freeBuffer();
|
((BufferBuilderExtension) scratch).flywheel$freeBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DrawBuffer getBuffer(RenderType renderType, RenderStage stage) {
|
public void markActive(DrawBuffer buffer) {
|
||||||
return RenderTypeExtension.getDrawBufferSet(renderType)
|
|
||||||
.getBuffer(stage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void markActive(RenderStage stage, DrawBuffer buffer) {
|
|
||||||
synchronized (activeBuffers) {
|
synchronized (activeBuffers) {
|
||||||
activeBuffers.get(stage)
|
activeBuffers.get(buffer.getRenderStage())
|
||||||
.add(buffer);
|
.add(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markInactive(RenderStage stage, DrawBuffer buffer) {
|
public void markInactive(DrawBuffer buffer) {
|
||||||
synchronized (activeBuffers) {
|
synchronized (activeBuffers) {
|
||||||
activeBuffers.get(stage)
|
activeBuffers.get(buffer.getRenderStage())
|
||||||
.remove(buffer);
|
.remove(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasStage(RenderStage stage) {
|
||||||
|
synchronized (activeBuffers) {
|
||||||
|
return !activeBuffers.get(stage)
|
||||||
|
.isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw and reset all DrawBuffers for the given RenderStage.
|
* Draw and reset all DrawBuffers for the given RenderStage.
|
||||||
*
|
*
|
||||||
|
@ -80,11 +79,4 @@ public class BatchingDrawTracker {
|
||||||
buffers.clear();
|
buffers.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasStage(RenderStage stage) {
|
|
||||||
synchronized (activeBuffers) {
|
|
||||||
return !activeBuffers.get(stage)
|
|
||||||
.isEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -6,8 +6,8 @@ import com.jozufozu.flywheel.api.instance.Instance;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||||
import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
|
import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
|
||||||
|
|
||||||
public class CPUInstancer<I extends Instance> extends AbstractInstancer<I> {
|
public class BatchedInstancer<I extends Instance> extends AbstractInstancer<I> {
|
||||||
public CPUInstancer(InstanceType<I> type) {
|
public BatchedInstancer(InstanceType<I> type) {
|
||||||
super(type);
|
super(type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.joml.Vector4fc;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.Flywheel;
|
import com.jozufozu.flywheel.Flywheel;
|
||||||
|
@ -149,9 +150,10 @@ public class BatchedMeshPool {
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BufferedMesh {
|
public class BufferedMesh {
|
||||||
public final Mesh mesh;
|
private final Mesh mesh;
|
||||||
private final int byteSize;
|
private final int byteSize;
|
||||||
private final int vertexCount;
|
private final int vertexCount;
|
||||||
|
private final Vector4fc boundingSphere;
|
||||||
|
|
||||||
private long byteIndex;
|
private long byteIndex;
|
||||||
private boolean deleted;
|
private boolean deleted;
|
||||||
|
@ -159,6 +161,7 @@ public class BatchedMeshPool {
|
||||||
private BufferedMesh(Mesh mesh, long byteIndex) {
|
private BufferedMesh(Mesh mesh, long byteIndex) {
|
||||||
this.mesh = mesh;
|
this.mesh = mesh;
|
||||||
vertexCount = mesh.getVertexCount();
|
vertexCount = mesh.getVertexCount();
|
||||||
|
boundingSphere = mesh.getBoundingSphere();
|
||||||
byteSize = vertexCount * vertexFormat.getVertexSize();
|
byteSize = vertexCount * vertexFormat.getVertexSize();
|
||||||
this.byteIndex = byteIndex;
|
this.byteIndex = byteIndex;
|
||||||
}
|
}
|
||||||
|
@ -171,6 +174,10 @@ public class BatchedMeshPool {
|
||||||
return vertexCount;
|
return vertexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vector4fc getBoundingSphere() {
|
||||||
|
return boundingSphere;
|
||||||
|
}
|
||||||
|
|
||||||
public VertexFormat getVertexFormat() {
|
public VertexFormat getVertexFormat() {
|
||||||
return vertexFormat;
|
return vertexFormat;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,39 +16,39 @@ import net.minecraft.client.renderer.RenderType;
|
||||||
/**
|
/**
|
||||||
* All the rendering that happens within a render stage.
|
* All the rendering that happens within a render stage.
|
||||||
*/
|
*/
|
||||||
public class BatchingStage implements SimplyComposedPlan<BatchContext> {
|
public class BatchedStagePlan implements SimplyComposedPlan<BatchContext> {
|
||||||
private final RenderStage stage;
|
private final RenderStage stage;
|
||||||
private final BatchingDrawTracker tracker;
|
private final BatchedDrawTracker tracker;
|
||||||
private final Map<RenderType, BufferPlan> buffers = new HashMap<>();
|
private final Map<RenderType, BufferPlan> bufferPlans = new HashMap<>();
|
||||||
|
|
||||||
public BatchingStage(RenderStage renderStage, BatchingDrawTracker tracker) {
|
public BatchedStagePlan(RenderStage renderStage, BatchedDrawTracker tracker) {
|
||||||
stage = renderStage;
|
stage = renderStage;
|
||||||
this.tracker = tracker;
|
this.tracker = tracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(TaskExecutor taskExecutor, BatchContext context, Runnable onCompletion) {
|
public void execute(TaskExecutor taskExecutor, BatchContext context, Runnable onCompletion) {
|
||||||
if (buffers.isEmpty()) {
|
if (isEmpty()) {
|
||||||
onCompletion.run();
|
onCompletion.run();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
taskExecutor.execute(() -> {
|
taskExecutor.execute(() -> {
|
||||||
var sync = new Synchronizer(buffers.size(), onCompletion);
|
var sync = new Synchronizer(bufferPlans.size(), onCompletion);
|
||||||
|
|
||||||
for (var buffer : buffers.values()) {
|
for (var plan : bufferPlans.values()) {
|
||||||
buffer.execute(taskExecutor, context, sync);
|
plan.execute(taskExecutor, context, sync);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void put(RenderType renderType, TransformCall<?> transformCall) {
|
public void put(RenderType renderType, TransformCall<?> transformCall) {
|
||||||
buffers.computeIfAbsent(renderType, type -> new BufferPlan(BatchingDrawTracker.getBuffer(type, stage)))
|
bufferPlans.computeIfAbsent(renderType, type -> new BufferPlan(DrawBuffer.get(type, stage)))
|
||||||
.add(transformCall);
|
.add(transformCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return buffers.isEmpty();
|
return bufferPlans.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BufferPlan implements SimplyComposedPlan<BatchContext> {
|
private class BufferPlan implements SimplyComposedPlan<BatchContext> {
|
||||||
|
@ -72,19 +72,17 @@ public class BatchingStage implements SimplyComposedPlan<BatchContext> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracker.markActive(stage, buffer);
|
tracker.markActive(buffer);
|
||||||
|
|
||||||
var vertexCounter = new AtomicInteger(0);
|
|
||||||
|
|
||||||
buffer.prepare(vertexCount);
|
buffer.prepare(vertexCount);
|
||||||
|
|
||||||
|
var vertexCounter = new AtomicInteger(0);
|
||||||
|
var planContext = new TransformCall.PlanContext(ctx.frustum(), vertexCounter, buffer, ctx.level(), ctx.matrices());
|
||||||
|
|
||||||
var synchronizer = new Synchronizer(transformCalls.size(), () -> {
|
var synchronizer = new Synchronizer(transformCalls.size(), () -> {
|
||||||
buffer.vertexCount(vertexCounter.get());
|
buffer.verticesToDraw(vertexCounter.get());
|
||||||
onCompletion.run();
|
onCompletion.run();
|
||||||
});
|
});
|
||||||
|
|
||||||
var planContext = new TransformCall.PlanContext(ctx, buffer, vertexCounter);
|
|
||||||
|
|
||||||
for (var transformCall : transformCalls) {
|
for (var transformCall : transformCalls) {
|
||||||
transformCall.plan()
|
transformCall.plan()
|
||||||
.execute(taskExecutor, planContext, synchronizer);
|
.execute(taskExecutor, planContext, synchronizer);
|
|
@ -24,11 +24,11 @@ import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
|
||||||
public class BatchingEngine extends AbstractEngine implements SimplyComposedPlan<RenderContext> {
|
public class BatchingEngine extends AbstractEngine implements SimplyComposedPlan<RenderContext> {
|
||||||
private final BatchingDrawTracker drawTracker = new BatchingDrawTracker();
|
private final BatchedDrawTracker drawTracker = new BatchedDrawTracker();
|
||||||
private final Map<InstancerKey<?>, CPUInstancer<?>> instancers = new HashMap<>();
|
private final Map<InstancerKey<?>, BatchedInstancer<?>> instancers = new HashMap<>();
|
||||||
private final List<UninitializedInstancer> uninitializedInstancers = new ArrayList<>();
|
private final List<UninitializedInstancer> uninitializedInstancers = new ArrayList<>();
|
||||||
private final List<CPUInstancer<?>> initializedInstancers = new ArrayList<>();
|
private final List<BatchedInstancer<?>> initializedInstancers = new ArrayList<>();
|
||||||
private final Map<RenderStage, BatchingStage> stages = new EnumMap<>(RenderStage.class);
|
private final Map<RenderStage, BatchedStagePlan> stagePlans = new EnumMap<>(RenderStage.class);
|
||||||
private final Map<VertexFormat, BatchedMeshPool> meshPools = new HashMap<>();
|
private final Map<VertexFormat, BatchedMeshPool> meshPools = new HashMap<>();
|
||||||
|
|
||||||
public BatchingEngine(int maxOriginDistance) {
|
public BatchingEngine(int maxOriginDistance) {
|
||||||
|
@ -36,8 +36,16 @@ public class BatchingEngine extends AbstractEngine implements SimplyComposedPlan
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public <I extends Instance> Instancer<I> instancer(InstanceType<I> type, Model model, RenderStage stage) {
|
public <I extends Instance> Instancer<I> instancer(InstanceType<I> type, Model model, RenderStage stage) {
|
||||||
return this.getInstancer(type, model, stage);
|
InstancerKey<I> key = new InstancerKey<>(type, model, stage);
|
||||||
|
BatchedInstancer<I> instancer = (BatchedInstancer<I>) instancers.get(key);
|
||||||
|
if (instancer == null) {
|
||||||
|
instancer = new BatchedInstancer<>(type);
|
||||||
|
instancers.put(key, instancer);
|
||||||
|
uninitializedInstancers.add(new UninitializedInstancer(instancer, model, stage));
|
||||||
|
}
|
||||||
|
return instancer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,11 +54,11 @@ public class BatchingEngine extends AbstractEngine implements SimplyComposedPlan
|
||||||
|
|
||||||
BatchContext ctx = BatchContext.create(context, renderOrigin);
|
BatchContext ctx = BatchContext.create(context, renderOrigin);
|
||||||
|
|
||||||
var sync = new Synchronizer(stages.values()
|
var sync = new Synchronizer(stagePlans.values()
|
||||||
.size(), onCompletion);
|
.size(), onCompletion);
|
||||||
|
|
||||||
for (var transformSet : stages.values()) {
|
for (var stagePlan : stagePlans.values()) {
|
||||||
transformSet.execute(taskExecutor, ctx, sync);
|
stagePlan.execute(taskExecutor, ctx, sync);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +75,7 @@ public class BatchingEngine extends AbstractEngine implements SimplyComposedPlan
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRenderOriginChanged() {
|
protected void onRenderOriginChanged() {
|
||||||
initializedInstancers.forEach(CPUInstancer::clear);
|
initializedInstancers.forEach(BatchedInstancer::clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -87,18 +95,6 @@ public class BatchingEngine extends AbstractEngine implements SimplyComposedPlan
|
||||||
info.add("Origin: " + renderOrigin.getX() + ", " + renderOrigin.getY() + ", " + renderOrigin.getZ());
|
info.add("Origin: " + renderOrigin.getX() + ", " + renderOrigin.getY() + ", " + renderOrigin.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <I extends Instance> Instancer<I> getInstancer(InstanceType<I> type, Model model, RenderStage stage) {
|
|
||||||
InstancerKey<I> key = new InstancerKey<>(type, model, stage);
|
|
||||||
CPUInstancer<I> instancer = (CPUInstancer<I>) instancers.get(key);
|
|
||||||
if (instancer == null) {
|
|
||||||
instancer = new CPUInstancer<>(type);
|
|
||||||
instancers.put(key, instancer);
|
|
||||||
uninitializedInstancers.add(new UninitializedInstancer(instancer, model, stage));
|
|
||||||
}
|
|
||||||
return instancer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void flush() {
|
private void flush() {
|
||||||
for (var instancer : uninitializedInstancers) {
|
for (var instancer : uninitializedInstancers) {
|
||||||
add(instancer.instancer(), instancer.model(), instancer.stage());
|
add(instancer.instancer(), instancer.model(), instancer.stage());
|
||||||
|
@ -110,14 +106,14 @@ public class BatchingEngine extends AbstractEngine implements SimplyComposedPlan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void add(CPUInstancer<?> instancer, Model model, RenderStage stage) {
|
private void add(BatchedInstancer<?> instancer, Model model, RenderStage stage) {
|
||||||
var batchingStage = stages.computeIfAbsent(stage, renderStage -> new BatchingStage(renderStage, drawTracker));
|
var stagePlan = stagePlans.computeIfAbsent(stage, renderStage -> new BatchedStagePlan(renderStage, drawTracker));
|
||||||
var meshes = model.getMeshes();
|
var meshes = model.getMeshes();
|
||||||
for (var entry : meshes.entrySet()) {
|
for (var entry : meshes.entrySet()) {
|
||||||
var material = entry.getKey();
|
var material = entry.getKey();
|
||||||
RenderType renderType = material.getBatchingRenderType();
|
RenderType renderType = material.getBatchingRenderType();
|
||||||
var transformCall = new TransformCall<>(instancer, material, alloc(entry.getValue(), renderType.format()));
|
var transformCall = new TransformCall<>(instancer, material, alloc(entry.getValue(), renderType.format()));
|
||||||
batchingStage.put(renderType, transformCall);
|
stagePlan.put(renderType, transformCall);
|
||||||
}
|
}
|
||||||
initializedInstancers.add(instancer);
|
initializedInstancers.add(instancer);
|
||||||
}
|
}
|
||||||
|
@ -127,6 +123,6 @@ public class BatchingEngine extends AbstractEngine implements SimplyComposedPlan
|
||||||
.alloc(mesh);
|
.alloc(mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
private record UninitializedInstancer(CPUInstancer<?> instancer, Model model, RenderStage stage) {
|
private record UninitializedInstancer(BatchedInstancer<?> instancer, Model model, RenderStage stage) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,11 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.event.ReloadRenderersEvent;
|
import com.jozufozu.flywheel.api.event.ReloadRenderersEvent;
|
||||||
|
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||||
import com.jozufozu.flywheel.api.vertex.ReusableVertexList;
|
import com.jozufozu.flywheel.api.vertex.ReusableVertexList;
|
||||||
import com.jozufozu.flywheel.api.vertex.VertexListProvider;
|
import com.jozufozu.flywheel.api.vertex.VertexListProvider;
|
||||||
import com.jozufozu.flywheel.extension.BufferBuilderExtension;
|
import com.jozufozu.flywheel.extension.BufferBuilderExtension;
|
||||||
|
import com.jozufozu.flywheel.extension.RenderTypeExtension;
|
||||||
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
|
||||||
|
@ -22,6 +24,7 @@ public class DrawBuffer {
|
||||||
private static final List<DrawBuffer> ALL = new ArrayList<>();
|
private static final List<DrawBuffer> ALL = new ArrayList<>();
|
||||||
|
|
||||||
private final RenderType renderType;
|
private final RenderType renderType;
|
||||||
|
private final RenderStage renderStage;
|
||||||
private final VertexFormat format;
|
private final VertexFormat format;
|
||||||
private final int stride;
|
private final int stride;
|
||||||
private final VertexListProvider provider;
|
private final VertexListProvider provider;
|
||||||
|
@ -31,9 +34,11 @@ public class DrawBuffer {
|
||||||
|
|
||||||
private boolean prepared;
|
private boolean prepared;
|
||||||
private int vertexCount;
|
private int vertexCount;
|
||||||
|
private int verticesToDraw;
|
||||||
|
|
||||||
public DrawBuffer(RenderType renderType, VertexFormat format, int stride, VertexListProvider provider) {
|
public DrawBuffer(RenderType renderType, RenderStage renderStage, VertexFormat format, int stride, VertexListProvider provider) {
|
||||||
this.renderType = renderType;
|
this.renderType = renderType;
|
||||||
|
this.renderStage = renderStage;
|
||||||
this.format = format;
|
this.format = format;
|
||||||
this.stride = stride;
|
this.stride = stride;
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
|
@ -52,6 +57,7 @@ public class DrawBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.vertexCount = vertexCount;
|
this.vertexCount = vertexCount;
|
||||||
|
verticesToDraw = this.vertexCount;
|
||||||
|
|
||||||
// Add one extra vertex to uphold the vanilla assumption that BufferBuilders have at least
|
// Add one extra vertex to uphold the vanilla assumption that BufferBuilders have at least
|
||||||
// enough buffer space for one more vertex. Rubidium checks for this extra space when popNextBuffer
|
// enough buffer space for one more vertex. Rubidium checks for this extra space when popNextBuffer
|
||||||
|
@ -69,15 +75,15 @@ public class DrawBuffer {
|
||||||
prepared = true;
|
prepared = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void vertexCount(int vertexCount) {
|
|
||||||
this.vertexCount = vertexCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReusableVertexList slice(int startVertex, int vertexCount) {
|
public ReusableVertexList slice(int startVertex, int vertexCount) {
|
||||||
if (!prepared) {
|
if (!prepared) {
|
||||||
throw new IllegalStateException("Cannot slice DrawBuffer that is not prepared!");
|
throw new IllegalStateException("Cannot slice DrawBuffer that is not prepared!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (startVertex + vertexCount > this.vertexCount) {
|
||||||
|
throw new IndexOutOfBoundsException("Vertex count greater than allocated: " + startVertex + " + " + vertexCount + " > " + this.vertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
ReusableVertexList vertexList = provider.createVertexList();
|
ReusableVertexList vertexList = provider.createVertexList();
|
||||||
vertexList.ptr(ptrForVertex(startVertex));
|
vertexList.ptr(ptrForVertex(startVertex));
|
||||||
vertexList.vertexCount(vertexCount);
|
vertexList.vertexCount(vertexCount);
|
||||||
|
@ -88,6 +94,10 @@ public class DrawBuffer {
|
||||||
return memory.ptr() + startVertex * stride;
|
return memory.ptr() + startVertex * stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void verticesToDraw(int verticesToDraw) {
|
||||||
|
this.verticesToDraw = verticesToDraw;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injects the backing buffer into the given builder and prepares it for rendering.
|
* Injects the backing buffer into the given builder and prepares it for rendering.
|
||||||
*
|
*
|
||||||
|
@ -99,13 +109,17 @@ public class DrawBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
bufferBuilder.flywheel$injectForRender(buffer, format, vertexCount);
|
bufferBuilder.flywheel$injectForRender(buffer, format, verticesToDraw);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RenderType getRenderType() {
|
public RenderType getRenderType() {
|
||||||
return renderType;
|
return renderType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RenderStage getRenderStage() {
|
||||||
|
return renderStage;
|
||||||
|
}
|
||||||
|
|
||||||
public VertexFormat getVertexFormat() {
|
public VertexFormat getVertexFormat() {
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
|
@ -118,11 +132,15 @@ public class DrawBuffer {
|
||||||
return vertexCount;
|
return vertexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getVerticesToDraw() {
|
||||||
|
return verticesToDraw;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {@code true} if the buffer has any vertices.
|
* @return {@code true} if the buffer has any vertices to draw.
|
||||||
*/
|
*/
|
||||||
public boolean hasVertices() {
|
public boolean hasVertices() {
|
||||||
return vertexCount > 0;
|
return verticesToDraw > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,6 +151,7 @@ public class DrawBuffer {
|
||||||
public void reset() {
|
public void reset() {
|
||||||
prepared = false;
|
prepared = false;
|
||||||
vertexCount = 0;
|
vertexCount = 0;
|
||||||
|
verticesToDraw = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void free() {
|
public void free() {
|
||||||
|
@ -150,4 +169,9 @@ public class DrawBuffer {
|
||||||
public static void onReloadRenderers(ReloadRenderersEvent event) {
|
public static void onReloadRenderers(ReloadRenderersEvent event) {
|
||||||
ALL.forEach(DrawBuffer::free);
|
ALL.forEach(DrawBuffer::free);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DrawBuffer get(RenderType renderType, RenderStage stage) {
|
||||||
|
return RenderTypeExtension.getDrawBufferSet(renderType)
|
||||||
|
.getBuffer(stage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,6 @@ public class DrawBufferSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DrawBuffer getBuffer(RenderStage stage) {
|
public DrawBuffer getBuffer(RenderStage stage) {
|
||||||
return buffers.computeIfAbsent(stage, $ -> new DrawBuffer(renderType, format, stride, provider));
|
return buffers.computeIfAbsent(stage, renderStage -> new DrawBuffer(renderType, renderStage, format, stride, provider));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.engine.batching;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import org.joml.FrustumIntersection;
|
||||||
import org.joml.Vector4f;
|
import org.joml.Vector4f;
|
||||||
import org.joml.Vector4fc;
|
import org.joml.Vector4fc;
|
||||||
|
|
||||||
|
@ -18,61 +19,51 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.math.Matrix3f;
|
import com.mojang.math.Matrix3f;
|
||||||
import com.mojang.math.Matrix4f;
|
import com.mojang.math.Matrix4f;
|
||||||
|
|
||||||
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
|
|
||||||
public class TransformCall<I extends Instance> {
|
public class TransformCall<I extends Instance> {
|
||||||
private final CPUInstancer<I> instancer;
|
private final BatchedInstancer<I> instancer;
|
||||||
private final int meshVertexCount;
|
private final int meshVertexCount;
|
||||||
private final InstanceVertexTransformer<I> instanceVertexTransformer;
|
|
||||||
private final MaterialVertexTransformer materialVertexTransformer;
|
|
||||||
private final InstanceBoundingSphereTransformer<I> boundingSphereTransformer;
|
|
||||||
private final Vector4fc boundingSphere;
|
|
||||||
|
|
||||||
private final Plan<PlanContext> drawPlan;
|
private final Plan<PlanContext> drawPlan;
|
||||||
|
|
||||||
public TransformCall(CPUInstancer<I> instancer, Material material, BatchedMeshPool.BufferedMesh mesh) {
|
public TransformCall(BatchedInstancer<I> instancer, Material material, BatchedMeshPool.BufferedMesh mesh) {
|
||||||
this.instancer = instancer;
|
this.instancer = instancer;
|
||||||
|
|
||||||
instanceVertexTransformer = instancer.type.getVertexTransformer();
|
InstanceVertexTransformer<I> instanceVertexTransformer = instancer.type.getVertexTransformer();
|
||||||
boundingSphereTransformer = instancer.type.getBoundingSphereTransformer();
|
InstanceBoundingSphereTransformer<I> boundingSphereTransformer = instancer.type.getBoundingSphereTransformer();
|
||||||
materialVertexTransformer = material.getVertexTransformer();
|
MaterialVertexTransformer materialVertexTransformer = material.getVertexTransformer();
|
||||||
|
|
||||||
meshVertexCount = mesh.getVertexCount();
|
meshVertexCount = mesh.getVertexCount();
|
||||||
boundingSphere = mesh.mesh.getBoundingSphere();
|
Vector4fc meshBoundingSphere = mesh.getBoundingSphere();
|
||||||
|
|
||||||
drawPlan = ForEachPlan.of(instancer::getAll, (instance, ctx) -> {
|
drawPlan = ForEachPlan.of(instancer::getAll, (instance, ctx) -> {
|
||||||
var boundingSphere = new Vector4f(this.boundingSphere);
|
var boundingSphere = new Vector4f(meshBoundingSphere);
|
||||||
|
|
||||||
boundingSphereTransformer.transform(boundingSphere, instance);
|
boundingSphereTransformer.transform(boundingSphere, instance);
|
||||||
|
|
||||||
if (!ctx.ctx.frustum()
|
if (!ctx.frustum
|
||||||
.testSphere(boundingSphere.x, boundingSphere.y, boundingSphere.z, boundingSphere.w)) {
|
.testSphere(boundingSphere.x, boundingSphere.y, boundingSphere.z, boundingSphere.w)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int baseVertex = ctx.vertexCount.getAndAdd(meshVertexCount);
|
final int baseVertex = ctx.vertexCounter.getAndAdd(meshVertexCount);
|
||||||
|
|
||||||
if (baseVertex + meshVertexCount > ctx.buffer.getVertexCount()) {
|
|
||||||
throw new IndexOutOfBoundsException("Vertex count greater than allocated: " + baseVertex + " + " + meshVertexCount + " > " + ctx.buffer.getVertexCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
var sub = ctx.buffer.slice(baseVertex, meshVertexCount);
|
var sub = ctx.buffer.slice(baseVertex, meshVertexCount);
|
||||||
|
|
||||||
mesh.copyTo(sub.ptr());
|
mesh.copyTo(sub.ptr());
|
||||||
|
instanceVertexTransformer.transform(sub, instance);
|
||||||
instanceVertexTransformer.transform(sub, instance, ctx.ctx.level());
|
materialVertexTransformer.transform(sub, ctx.level);
|
||||||
|
applyMatrices(sub, ctx.matrices);
|
||||||
materialVertexTransformer.transform(sub, ctx.ctx.level());
|
|
||||||
applyMatrices(sub, ctx.ctx.matrices());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTotalVertexCount() {
|
|
||||||
return meshVertexCount * instancer.getInstanceCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setup() {
|
public void setup() {
|
||||||
instancer.update();
|
instancer.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getTotalVertexCount() {
|
||||||
|
return meshVertexCount * instancer.getInstanceCount();
|
||||||
|
}
|
||||||
|
|
||||||
public Plan<PlanContext> plan() {
|
public Plan<PlanContext> plan() {
|
||||||
return drawPlan;
|
return drawPlan;
|
||||||
}
|
}
|
||||||
|
@ -87,6 +78,6 @@ public class TransformCall<I extends Instance> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record PlanContext(BatchContext ctx, DrawBuffer buffer, AtomicInteger vertexCount) {
|
public record PlanContext(FrustumIntersection frustum, AtomicInteger vertexCounter, DrawBuffer buffer, ClientLevel level, PoseStack.Pose matrices) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,13 @@ package com.jozufozu.flywheel.backend.engine.instancing;
|
||||||
import com.jozufozu.flywheel.gl.array.GlVertexArray;
|
import com.jozufozu.flywheel.gl.array.GlVertexArray;
|
||||||
|
|
||||||
public class DrawCall {
|
public class DrawCall {
|
||||||
private final GPUInstancer<?> instancer;
|
private final InstancedInstancer<?> instancer;
|
||||||
private final InstancedMeshPool.BufferedMesh mesh;
|
private final InstancedMeshPool.BufferedMesh mesh;
|
||||||
|
|
||||||
private final int meshAttributes;
|
private final int meshAttributes;
|
||||||
private GlVertexArray vao;
|
private GlVertexArray vao;
|
||||||
|
|
||||||
public DrawCall(GPUInstancer<?> instancer, InstancedMeshPool.BufferedMesh mesh) {
|
public DrawCall(InstancedInstancer<?> instancer, InstancedMeshPool.BufferedMesh mesh) {
|
||||||
this.instancer = instancer;
|
this.instancer = instancer;
|
||||||
this.mesh = mesh;
|
this.mesh = mesh;
|
||||||
|
|
||||||
|
|
|
@ -22,10 +22,10 @@ import com.jozufozu.flywheel.api.model.Model;
|
||||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||||
import com.jozufozu.flywheel.backend.engine.InstancerKey;
|
import com.jozufozu.flywheel.backend.engine.InstancerKey;
|
||||||
|
|
||||||
public class InstancingDrawManager {
|
public class InstancedDrawManager {
|
||||||
private final Map<InstancerKey<?>, GPUInstancer<?>> instancers = new HashMap<>();
|
private final Map<InstancerKey<?>, InstancedInstancer<?>> instancers = new HashMap<>();
|
||||||
private final List<UninitializedInstancer> uninitializedInstancers = new ArrayList<>();
|
private final List<UninitializedInstancer> uninitializedInstancers = new ArrayList<>();
|
||||||
private final List<GPUInstancer<?>> initializedInstancers = new ArrayList<>();
|
private final List<InstancedInstancer<?>> initializedInstancers = new ArrayList<>();
|
||||||
private final Map<RenderStage, DrawSet> drawSets = new EnumMap<>(RenderStage.class);
|
private final Map<RenderStage, DrawSet> drawSets = new EnumMap<>(RenderStage.class);
|
||||||
private final Map<VertexType, InstancedMeshPool> meshPools = new HashMap<>();
|
private final Map<VertexType, InstancedMeshPool> meshPools = new HashMap<>();
|
||||||
|
|
||||||
|
@ -36,9 +36,9 @@ public class InstancingDrawManager {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <I extends Instance> Instancer<I> getInstancer(InstanceType<I> type, Model model, RenderStage stage) {
|
public <I extends Instance> Instancer<I> getInstancer(InstanceType<I> type, Model model, RenderStage stage) {
|
||||||
InstancerKey<I> key = new InstancerKey<>(type, model, stage);
|
InstancerKey<I> key = new InstancerKey<>(type, model, stage);
|
||||||
GPUInstancer<I> instancer = (GPUInstancer<I>) instancers.get(key);
|
InstancedInstancer<I> instancer = (InstancedInstancer<I>) instancers.get(key);
|
||||||
if (instancer == null) {
|
if (instancer == null) {
|
||||||
instancer = new GPUInstancer<>(type);
|
instancer = new InstancedInstancer<>(type);
|
||||||
instancers.put(key, instancer);
|
instancers.put(key, instancer);
|
||||||
uninitializedInstancers.add(new UninitializedInstancer(instancer, model, stage));
|
uninitializedInstancers.add(new UninitializedInstancer(instancer, model, stage));
|
||||||
}
|
}
|
||||||
|
@ -67,15 +67,15 @@ public class InstancingDrawManager {
|
||||||
.forEach(DrawSet::delete);
|
.forEach(DrawSet::delete);
|
||||||
drawSets.clear();
|
drawSets.clear();
|
||||||
|
|
||||||
initializedInstancers.forEach(GPUInstancer::delete);
|
initializedInstancers.forEach(InstancedInstancer::delete);
|
||||||
initializedInstancers.clear();
|
initializedInstancers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearInstancers() {
|
public void clearInstancers() {
|
||||||
initializedInstancers.forEach(GPUInstancer::clear);
|
initializedInstancers.forEach(InstancedInstancer::clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void add(GPUInstancer<?> instancer, Model model, RenderStage stage) {
|
private void add(InstancedInstancer<?> instancer, Model model, RenderStage stage) {
|
||||||
instancer.init();
|
instancer.init();
|
||||||
DrawSet drawSet = drawSets.computeIfAbsent(stage, DrawSet::new);
|
DrawSet drawSet = drawSets.computeIfAbsent(stage, DrawSet::new);
|
||||||
var meshes = model.getMeshes();
|
var meshes = model.getMeshes();
|
||||||
|
@ -129,6 +129,6 @@ public class InstancingDrawManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private record UninitializedInstancer(GPUInstancer<?> instancer, Model model, RenderStage stage) {
|
private record UninitializedInstancer(InstancedInstancer<?> instancer, Model model, RenderStage stage) {
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,14 +14,14 @@ import com.jozufozu.flywheel.gl.buffer.GlBuffer;
|
||||||
import com.jozufozu.flywheel.gl.buffer.GlBufferUsage;
|
import com.jozufozu.flywheel.gl.buffer.GlBufferUsage;
|
||||||
import com.jozufozu.flywheel.gl.buffer.MappedBuffer;
|
import com.jozufozu.flywheel.gl.buffer.MappedBuffer;
|
||||||
|
|
||||||
public class GPUInstancer<I extends Instance> extends AbstractInstancer<I> {
|
public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I> {
|
||||||
private final BufferLayout instanceFormat;
|
private final BufferLayout instanceFormat;
|
||||||
private final int instanceStride;
|
private final int instanceStride;
|
||||||
|
|
||||||
private final Set<GlVertexArray> boundTo = new HashSet<>();
|
private final Set<GlVertexArray> boundTo = new HashSet<>();
|
||||||
private GlBuffer vbo;
|
private GlBuffer vbo;
|
||||||
|
|
||||||
public GPUInstancer(InstanceType<I> type) {
|
public InstancedInstancer(InstanceType<I> type) {
|
||||||
super(type);
|
super(type);
|
||||||
instanceFormat = type.getLayout();
|
instanceFormat = type.getLayout();
|
||||||
instanceStride = instanceFormat.getStride();
|
instanceStride = instanceFormat.getStride();
|
|
@ -26,7 +26,7 @@ import net.minecraft.client.Minecraft;
|
||||||
|
|
||||||
public class InstancingEngine extends AbstractEngine {
|
public class InstancingEngine extends AbstractEngine {
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final InstancingDrawManager drawManager = new InstancingDrawManager();
|
private final InstancedDrawManager drawManager = new InstancedDrawManager();
|
||||||
|
|
||||||
public InstancingEngine(int maxOriginDistance, Context context) {
|
public InstancingEngine(int maxOriginDistance, Context context) {
|
||||||
super(maxOriginDistance);
|
super(maxOriginDistance);
|
||||||
|
@ -77,7 +77,7 @@ public class InstancingEngine extends AbstractEngine {
|
||||||
RenderSystem.enableCull();
|
RenderSystem.enableCull();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void render(InstancingDrawManager.DrawSet drawSet) {
|
private void render(InstancedDrawManager.DrawSet drawSet) {
|
||||||
for (var entry : drawSet) {
|
for (var entry : drawSet) {
|
||||||
var shader = entry.getKey();
|
var shader = entry.getKey();
|
||||||
var drawCalls = entry.getValue();
|
var drawCalls = entry.getValue();
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package com.jozufozu.flywheel.impl;
|
package com.jozufozu.flywheel.impl.vertex;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.vertex.VertexListProvider;
|
import com.jozufozu.flywheel.api.vertex.VertexListProvider;
|
||||||
import com.jozufozu.flywheel.extension.VertexFormatExtension;
|
import com.jozufozu.flywheel.extension.VertexFormatExtension;
|
||||||
import com.jozufozu.flywheel.impl.vertex.InferredVertexListProviderImpl;
|
|
||||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
|
||||||
// TODO: Add freezing
|
// TODO: Add freezing
|
|
@ -1,4 +1,4 @@
|
||||||
package com.jozufozu.flywheel.impl;
|
package com.jozufozu.flywheel.impl.visualization;
|
||||||
|
|
||||||
public record TickContext(double cameraX, double cameraY, double cameraZ) {
|
public record TickContext(double cameraX, double cameraY, double cameraZ) {
|
||||||
}
|
}
|
|
@ -17,7 +17,6 @@ import com.jozufozu.flywheel.backend.task.FlwTaskExecutor;
|
||||||
import com.jozufozu.flywheel.backend.task.ParallelTaskExecutor;
|
import com.jozufozu.flywheel.backend.task.ParallelTaskExecutor;
|
||||||
import com.jozufozu.flywheel.config.FlwCommands;
|
import com.jozufozu.flywheel.config.FlwCommands;
|
||||||
import com.jozufozu.flywheel.config.FlwConfig;
|
import com.jozufozu.flywheel.config.FlwConfig;
|
||||||
import com.jozufozu.flywheel.impl.TickContext;
|
|
||||||
import com.jozufozu.flywheel.impl.visualization.manager.BlockEntityVisualManager;
|
import com.jozufozu.flywheel.impl.visualization.manager.BlockEntityVisualManager;
|
||||||
import com.jozufozu.flywheel.impl.visualization.manager.EffectVisualManager;
|
import com.jozufozu.flywheel.impl.visualization.manager.EffectVisualManager;
|
||||||
import com.jozufozu.flywheel.impl.visualization.manager.EntityVisualManager;
|
import com.jozufozu.flywheel.impl.visualization.manager.EntityVisualManager;
|
||||||
|
@ -59,7 +58,7 @@ public class VisualWorld implements AutoCloseable {
|
||||||
tickPlan = blockEntities.createTickPlan()
|
tickPlan = blockEntities.createTickPlan()
|
||||||
.and(entities.createTickPlan())
|
.and(entities.createTickPlan())
|
||||||
.and(effects.createTickPlan())
|
.and(effects.createTickPlan())
|
||||||
.maybeSimplify();
|
.simplify();
|
||||||
framePlan = new FramePlan();
|
framePlan = new FramePlan();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ import com.jozufozu.flywheel.api.task.Plan;
|
||||||
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
|
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
|
||||||
import com.jozufozu.flywheel.api.visual.VisualTickContext;
|
import com.jozufozu.flywheel.api.visual.VisualTickContext;
|
||||||
import com.jozufozu.flywheel.config.FlwConfig;
|
import com.jozufozu.flywheel.config.FlwConfig;
|
||||||
import com.jozufozu.flywheel.impl.TickContext;
|
|
||||||
import com.jozufozu.flywheel.impl.visualization.FrameContext;
|
import com.jozufozu.flywheel.impl.visualization.FrameContext;
|
||||||
|
import com.jozufozu.flywheel.impl.visualization.TickContext;
|
||||||
import com.jozufozu.flywheel.impl.visualization.ratelimit.BandedPrimeLimiter;
|
import com.jozufozu.flywheel.impl.visualization.ratelimit.BandedPrimeLimiter;
|
||||||
import com.jozufozu.flywheel.impl.visualization.ratelimit.DistanceUpdateLimiterImpl;
|
import com.jozufozu.flywheel.impl.visualization.ratelimit.DistanceUpdateLimiterImpl;
|
||||||
import com.jozufozu.flywheel.impl.visualization.ratelimit.NonLimiter;
|
import com.jozufozu.flywheel.impl.visualization.ratelimit.NonLimiter;
|
||||||
|
|
|
@ -38,9 +38,9 @@ public class VisualUpdatePlan<C> implements SimplyComposedPlan<C> {
|
||||||
@NotNull
|
@NotNull
|
||||||
private Plan<C> updatePlans() {
|
private Plan<C> updatePlans() {
|
||||||
if (plan == null) {
|
if (plan == null) {
|
||||||
plan = new NestedPlan<>(initializer.get()).maybeSimplify();
|
plan = new NestedPlan<>(initializer.get()).simplify();
|
||||||
} else if (needsSimplify) {
|
} else if (needsSimplify) {
|
||||||
plan = plan.maybeSimplify();
|
plan = plan.simplify();
|
||||||
}
|
}
|
||||||
|
|
||||||
needsSimplify = false;
|
needsSimplify = false;
|
||||||
|
|
|
@ -48,7 +48,7 @@ public class OrientedType implements InstanceType<OrientedInstance> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InstanceVertexTransformer<OrientedInstance> getVertexTransformer() {
|
public InstanceVertexTransformer<OrientedInstance> getVertexTransformer() {
|
||||||
return (vertexList, instance, level) -> {
|
return (vertexList, instance) -> {
|
||||||
Quaternion q = new Quaternion(instance.qX, instance.qY, instance.qZ, instance.qW);
|
Quaternion q = new Quaternion(instance.qX, instance.qY, instance.qZ, instance.qW);
|
||||||
|
|
||||||
Matrix4f modelMatrix = new Matrix4f();
|
Matrix4f modelMatrix = new Matrix4f();
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class TransformedType implements InstanceType<TransformedInstance> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InstanceVertexTransformer<TransformedInstance> getVertexTransformer() {
|
public InstanceVertexTransformer<TransformedInstance> getVertexTransformer() {
|
||||||
return (vertexList, instance, level) -> {
|
return (vertexList, instance) -> {
|
||||||
float r = RenderMath.uf(instance.r);
|
float r = RenderMath.uf(instance.r);
|
||||||
float g = RenderMath.uf(instance.g);
|
float g = RenderMath.uf(instance.g);
|
||||||
float b = RenderMath.uf(instance.b);
|
float b = RenderMath.uf(instance.b);
|
||||||
|
|
|
@ -14,9 +14,9 @@ public record BarrierPlan<C>(Plan<C> first, Plan<C> second) implements SimplyCom
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Plan<C> maybeSimplify() {
|
public Plan<C> simplify() {
|
||||||
var first = this.first.maybeSimplify();
|
var first = this.first.simplify();
|
||||||
var second = this.second.maybeSimplify();
|
var second = this.second.simplify();
|
||||||
|
|
||||||
if (first == UnitPlan.of()) {
|
if (first == UnitPlan.of()) {
|
||||||
return second;
|
return second;
|
||||||
|
|
|
@ -13,8 +13,8 @@ public record MapContextPlan<C, D>(Function<C, D> map, Plan<D> plan) implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Plan<C> maybeSimplify() {
|
public Plan<C> simplify() {
|
||||||
var maybeSimplified = plan.maybeSimplify();
|
var maybeSimplified = plan.simplify();
|
||||||
|
|
||||||
if (maybeSimplified instanceof UnitPlan) {
|
if (maybeSimplified instanceof UnitPlan) {
|
||||||
return UnitPlan.of();
|
return UnitPlan.of();
|
||||||
|
|
|
@ -44,14 +44,14 @@ public record NestedPlan<C>(List<Plan<C>> parallelPlans) implements SimplyCompos
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Plan<C> maybeSimplify() {
|
public Plan<C> simplify() {
|
||||||
if (parallelPlans.isEmpty()) {
|
if (parallelPlans.isEmpty()) {
|
||||||
return UnitPlan.of();
|
return UnitPlan.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parallelPlans.size() == 1) {
|
if (parallelPlans.size() == 1) {
|
||||||
return parallelPlans.get(0)
|
return parallelPlans.get(0)
|
||||||
.maybeSimplify();
|
.simplify();
|
||||||
}
|
}
|
||||||
|
|
||||||
var simplifiedTasks = new ArrayList<ContextConsumer<C>>();
|
var simplifiedTasks = new ArrayList<ContextConsumer<C>>();
|
||||||
|
@ -59,7 +59,7 @@ public record NestedPlan<C>(List<Plan<C>> parallelPlans) implements SimplyCompos
|
||||||
var toVisit = new ArrayDeque<>(parallelPlans);
|
var toVisit = new ArrayDeque<>(parallelPlans);
|
||||||
while (!toVisit.isEmpty()) {
|
while (!toVisit.isEmpty()) {
|
||||||
var plan = toVisit.pop()
|
var plan = toVisit.pop()
|
||||||
.maybeSimplify();
|
.simplify();
|
||||||
|
|
||||||
if (plan == UnitPlan.of()) {
|
if (plan == UnitPlan.of()) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -45,7 +45,7 @@ public record SimplePlan<C>(List<ContextConsumer<C>> parallelTasks) implements S
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Plan<C> maybeSimplify() {
|
public Plan<C> simplify() {
|
||||||
if (parallelTasks.isEmpty()) {
|
if (parallelTasks.isEmpty()) {
|
||||||
return UnitPlan.of();
|
return UnitPlan.of();
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ public interface SimplyComposedPlan<C> extends Plan<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default Plan<C> maybeSimplify() {
|
default Plan<C> simplify() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class UnitPlan<C> implements Plan<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Plan<C> maybeSimplify() {
|
public Plan<C> simplify() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,36 +15,36 @@ public class PlanSimplificationTest {
|
||||||
@Test
|
@Test
|
||||||
void emptyPlans() {
|
void emptyPlans() {
|
||||||
var empty = NestedPlan.of();
|
var empty = NestedPlan.of();
|
||||||
Assertions.assertEquals(empty.maybeSimplify(), UnitPlan.of());
|
Assertions.assertEquals(empty.simplify(), UnitPlan.of());
|
||||||
|
|
||||||
var simpleEmpty = SimplePlan.of();
|
var simpleEmpty = SimplePlan.of();
|
||||||
Assertions.assertEquals(simpleEmpty.maybeSimplify(), UnitPlan.of());
|
Assertions.assertEquals(simpleEmpty.simplify(), UnitPlan.of());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void nestedSimplePlans() {
|
void nestedSimplePlans() {
|
||||||
var twoSimple = NestedPlan.of(SimplePlan.of(NOOP, NOOP, NOOP), SIMPLE);
|
var twoSimple = NestedPlan.of(SimplePlan.of(NOOP, NOOP, NOOP), SIMPLE);
|
||||||
Assertions.assertEquals(twoSimple.maybeSimplify(), SimplePlan.of(NOOP, NOOP, NOOP, NOOP));
|
Assertions.assertEquals(twoSimple.simplify(), SimplePlan.of(NOOP, NOOP, NOOP, NOOP));
|
||||||
|
|
||||||
var threeSimple = NestedPlan.of(SIMPLE, SIMPLE, SIMPLE);
|
var threeSimple = NestedPlan.of(SIMPLE, SIMPLE, SIMPLE);
|
||||||
Assertions.assertEquals(threeSimple.maybeSimplify(), SimplePlan.of(NOOP, NOOP, NOOP));
|
Assertions.assertEquals(threeSimple.simplify(), SimplePlan.of(NOOP, NOOP, NOOP));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void oneNestedPlan() {
|
void oneNestedPlan() {
|
||||||
var oneSimple = NestedPlan.of(SIMPLE);
|
var oneSimple = NestedPlan.of(SIMPLE);
|
||||||
|
|
||||||
Assertions.assertEquals(oneSimple.maybeSimplify(), SIMPLE);
|
Assertions.assertEquals(oneSimple.simplify(), SIMPLE);
|
||||||
|
|
||||||
var mainThreadNoop = new OnMainThreadPlan<>(NOOP);
|
var mainThreadNoop = new OnMainThreadPlan<>(NOOP);
|
||||||
var oneMainThread = NestedPlan.of(mainThreadNoop);
|
var oneMainThread = NestedPlan.of(mainThreadNoop);
|
||||||
|
|
||||||
Assertions.assertEquals(oneMainThread.maybeSimplify(), mainThreadNoop);
|
Assertions.assertEquals(oneMainThread.simplify(), mainThreadNoop);
|
||||||
|
|
||||||
var barrier = new BarrierPlan<>(SIMPLE, SIMPLE);
|
var barrier = new BarrierPlan<>(SIMPLE, SIMPLE);
|
||||||
var oneBarrier = NestedPlan.of(barrier);
|
var oneBarrier = NestedPlan.of(barrier);
|
||||||
|
|
||||||
Assertions.assertEquals(oneBarrier.maybeSimplify(), barrier);
|
Assertions.assertEquals(oneBarrier.simplify(), barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -52,16 +52,16 @@ public class PlanSimplificationTest {
|
||||||
var outer = NestedPlan.of(SIMPLE);
|
var outer = NestedPlan.of(SIMPLE);
|
||||||
var outermost = NestedPlan.of(outer);
|
var outermost = NestedPlan.of(outer);
|
||||||
|
|
||||||
Assertions.assertEquals(outermost.maybeSimplify(), SIMPLE);
|
Assertions.assertEquals(outermost.simplify(), SIMPLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void nestedUnitPlan() {
|
void nestedUnitPlan() {
|
||||||
var onlyUnit = NestedPlan.of(UnitPlan.of(), UnitPlan.of(), UnitPlan.of());
|
var onlyUnit = NestedPlan.of(UnitPlan.of(), UnitPlan.of(), UnitPlan.of());
|
||||||
Assertions.assertEquals(onlyUnit.maybeSimplify(), UnitPlan.of());
|
Assertions.assertEquals(onlyUnit.simplify(), UnitPlan.of());
|
||||||
|
|
||||||
var unitAndSimple = NestedPlan.of(UnitPlan.of(), UnitPlan.of(), SIMPLE);
|
var unitAndSimple = NestedPlan.of(UnitPlan.of(), UnitPlan.of(), SIMPLE);
|
||||||
Assertions.assertEquals(unitAndSimple.maybeSimplify(), SIMPLE);
|
Assertions.assertEquals(unitAndSimple.simplify(), SIMPLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -70,11 +70,11 @@ public class PlanSimplificationTest {
|
||||||
});
|
});
|
||||||
|
|
||||||
var nested = NestedPlan.of(mainThreadNoop, SIMPLE);
|
var nested = NestedPlan.of(mainThreadNoop, SIMPLE);
|
||||||
Assertions.assertEquals(nested.maybeSimplify(), nested); // cannot simplify
|
Assertions.assertEquals(nested.simplify(), nested); // cannot simplify
|
||||||
|
|
||||||
var barrier = new BarrierPlan<>(SIMPLE, SIMPLE);
|
var barrier = new BarrierPlan<>(SIMPLE, SIMPLE);
|
||||||
var complex = NestedPlan.of(barrier, nested);
|
var complex = NestedPlan.of(barrier, nested);
|
||||||
Assertions.assertEquals(complex.maybeSimplify(), NestedPlan.of(barrier, mainThreadNoop, SIMPLE));
|
Assertions.assertEquals(complex.simplify(), NestedPlan.of(barrier, mainThreadNoop, SIMPLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -84,7 +84,7 @@ public class PlanSimplificationTest {
|
||||||
var barrier = new BarrierPlan<>(SIMPLE, SIMPLE);
|
var barrier = new BarrierPlan<>(SIMPLE, SIMPLE);
|
||||||
var oneMainThread = NestedPlan.of(mainThreadNoop, NestedPlan.of(mainThreadNoop, barrier, barrier));
|
var oneMainThread = NestedPlan.of(mainThreadNoop, NestedPlan.of(mainThreadNoop, barrier, barrier));
|
||||||
|
|
||||||
Assertions.assertEquals(oneMainThread.maybeSimplify(), NestedPlan.of(mainThreadNoop, mainThreadNoop, barrier, barrier));
|
Assertions.assertEquals(oneMainThread.simplify(), NestedPlan.of(mainThreadNoop, mainThreadNoop, barrier, barrier));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -92,21 +92,21 @@ public class PlanSimplificationTest {
|
||||||
var barrier = new BarrierPlan<>(SIMPLE, SIMPLE);
|
var barrier = new BarrierPlan<>(SIMPLE, SIMPLE);
|
||||||
var oneMainThread = NestedPlan.of(barrier, NestedPlan.of(UnitPlan.of(), UnitPlan.of()));
|
var oneMainThread = NestedPlan.of(barrier, NestedPlan.of(UnitPlan.of(), UnitPlan.of()));
|
||||||
|
|
||||||
Assertions.assertEquals(oneMainThread.maybeSimplify(), barrier);
|
Assertions.assertEquals(oneMainThread.simplify(), barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void barrierPlan() {
|
void barrierPlan() {
|
||||||
var doubleUnit = new BarrierPlan<>(UnitPlan.of(), UnitPlan.of());
|
var doubleUnit = new BarrierPlan<>(UnitPlan.of(), UnitPlan.of());
|
||||||
Assertions.assertEquals(doubleUnit.maybeSimplify(), UnitPlan.of());
|
Assertions.assertEquals(doubleUnit.simplify(), UnitPlan.of());
|
||||||
|
|
||||||
var simpleThenUnit = new BarrierPlan<>(SIMPLE, UnitPlan.of());
|
var simpleThenUnit = new BarrierPlan<>(SIMPLE, UnitPlan.of());
|
||||||
Assertions.assertEquals(simpleThenUnit.maybeSimplify(), SIMPLE);
|
Assertions.assertEquals(simpleThenUnit.simplify(), SIMPLE);
|
||||||
|
|
||||||
var unitThenSimple = new BarrierPlan<>(UnitPlan.of(), SIMPLE);
|
var unitThenSimple = new BarrierPlan<>(UnitPlan.of(), SIMPLE);
|
||||||
Assertions.assertEquals(unitThenSimple.maybeSimplify(), SIMPLE);
|
Assertions.assertEquals(unitThenSimple.simplify(), SIMPLE);
|
||||||
|
|
||||||
var simpleThenSimple = new BarrierPlan<>(SIMPLE, SIMPLE);
|
var simpleThenSimple = new BarrierPlan<>(SIMPLE, SIMPLE);
|
||||||
Assertions.assertEquals(simpleThenSimple.maybeSimplify(), new BarrierPlan<>(SIMPLE, SIMPLE));
|
Assertions.assertEquals(simpleThenSimple.simplify(), new BarrierPlan<>(SIMPLE, SIMPLE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue