From bb8cae6c6d9d9de23892fbf1630d309f84e89834 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Mon, 11 Apr 2022 15:11:39 -0700 Subject: [PATCH] Material refactor pt 2 - Inline all the things - Now MaterialManager -> Material -> Instancer - ModelSuppliers store RenderType - Currently broken, it only renders chunk layers so vanilla instances are invisible --- .../java/com/jozufozu/flywheel/Flywheel.java | 2 + .../com/jozufozu/flywheel/api/Material.java | 25 +--- .../flywheel/api/MaterialManager.java | 35 +---- .../jozufozu/flywheel/api/ModelSupplier.java | 11 -- .../backend/instancing/AbstractInstancer.java | 8 +- .../backend/instancing/Renderable.java | 6 + .../instancing/batching/BatchedMaterial.java | 6 +- .../instancing/batching/BatchingEngine.java | 8 +- .../instancing/batching/CPUInstancer.java | 6 +- .../blockentity/BlockEntityInstance.java | 6 +- .../instancing/instancing/GPUInstancer.java | 22 ++- .../instancing/InstancedMaterial.java | 34 ++++- .../instancing/InstancedMaterialGroup.java | 107 +------------- .../instancing/InstancingEngine.java | 137 ++++++++++++------ .../flywheel/backend/model/ModelPool.java | 1 + .../jozufozu/flywheel/core/ModelSupplier.java | 44 ++++++ .../com/jozufozu/flywheel/core/Models.java | 24 ++- .../flywheel/core/SimpleModelSupplier.java | 25 ---- .../core/compile/ProgramCompiler.java | 2 +- .../core/crumbling/CrumblingGroup.java | 2 +- .../java/com/jozufozu/flywheel/util/Lazy.java | 5 + .../flywheel/vanilla/BellInstance.java | 9 +- .../flywheel/vanilla/ChestInstance.java | 17 +-- .../flywheel/vanilla/MinecartInstance.java | 15 +- .../flywheel/vanilla/ShulkerBoxInstance.java | 18 +-- 25 files changed, 264 insertions(+), 311 deletions(-) delete mode 100644 src/main/java/com/jozufozu/flywheel/api/ModelSupplier.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/Renderable.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/ModelSupplier.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/SimpleModelSupplier.java diff --git a/src/main/java/com/jozufozu/flywheel/Flywheel.java b/src/main/java/com/jozufozu/flywheel/Flywheel.java index 3ae7e9691..8a05d51fd 100644 --- a/src/main/java/com/jozufozu/flywheel/Flywheel.java +++ b/src/main/java/com/jozufozu/flywheel/Flywheel.java @@ -9,6 +9,7 @@ import com.jozufozu.flywheel.config.BackendTypeArgument; import com.jozufozu.flywheel.config.FlwCommands; import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.core.Contexts; +import com.jozufozu.flywheel.core.Models; import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.core.StitchedSprite; import com.jozufozu.flywheel.core.compile.ProgramCompiler; @@ -70,6 +71,7 @@ public class Flywheel { forgeEventBus.addListener(FlwCommands::registerClientCommands); forgeEventBus.addListener(ProgramCompiler::invalidateAll); + forgeEventBus.addListener(Models::onReload); modEventBus.addListener(Contexts::flwInit); modEventBus.addListener(PartialModel::onModelRegistry); diff --git a/src/main/java/com/jozufozu/flywheel/api/Material.java b/src/main/java/com/jozufozu/flywheel/api/Material.java index 01c7d8b0c..345c3e3ed 100644 --- a/src/main/java/com/jozufozu/flywheel/api/Material.java +++ b/src/main/java/com/jozufozu/flywheel/api/Material.java @@ -1,14 +1,6 @@ package com.jozufozu.flywheel.api; -import java.util.function.Supplier; - -import com.jozufozu.flywheel.core.Models; -import com.jozufozu.flywheel.core.PartialModel; -import com.jozufozu.flywheel.core.model.ModelUtil; -import com.mojang.blaze3d.vertex.PoseStack; - -import net.minecraft.core.Direction; -import net.minecraft.world.level.block.state.BlockState; +import com.jozufozu.flywheel.core.ModelSupplier; public interface Material { @@ -20,19 +12,4 @@ public interface Material { */ Instancer model(ModelSupplier modelKey); - default Instancer getModel(PartialModel partial) { - return model(Models.partial(partial)); - } - - default Instancer getModel(PartialModel partial, Direction dir) { - return model(Models.partial(partial, dir, () -> ModelUtil.rotateToFace(dir))); - } - - default Instancer getModel(PartialModel partial, Direction dir, Supplier modelTransform) { - return model(Models.partial(partial, dir, modelTransform)); - } - - default Instancer getModel(BlockState toRender) { - return model(Models.block(toRender)); - } } diff --git a/src/main/java/com/jozufozu/flywheel/api/MaterialManager.java b/src/main/java/com/jozufozu/flywheel/api/MaterialManager.java index c5e82baf8..62047cbbc 100644 --- a/src/main/java/com/jozufozu/flywheel/api/MaterialManager.java +++ b/src/main/java/com/jozufozu/flywheel/api/MaterialManager.java @@ -1,42 +1,15 @@ package com.jozufozu.flywheel.api; +import com.jozufozu.flywheel.api.struct.StructType; +import com.jozufozu.flywheel.backend.instancing.instancing.InstancedMaterial; + import net.minecraft.client.renderer.RenderType; import net.minecraft.core.Vec3i; public interface MaterialManager { - /** - * Get a material group that will render in the given layer with the given state. - * - * @param layer The {@link RenderLayer} you want to draw in. - * @param type The {@link RenderType} you need to draw with. - * @return A material group whose children will - */ - MaterialGroup state(RenderLayer layer, RenderType type); + InstancedMaterial material(StructType type); Vec3i getOriginCoordinate(); - default MaterialGroup solid(RenderType state) { - return state(RenderLayer.SOLID, state); - } - - default MaterialGroup cutout(RenderType state) { - return state(RenderLayer.CUTOUT, state); - } - - default MaterialGroup transparent(RenderType state) { - return state(RenderLayer.TRANSPARENT, state); - } - - default MaterialGroup defaultSolid() { - return solid(RenderType.solid()); - } - - default MaterialGroup defaultCutout() { - return cutout(RenderType.cutout()); - } - - default MaterialGroup defaultTransparent() { - return transparent(RenderType.translucent()); - } } diff --git a/src/main/java/com/jozufozu/flywheel/api/ModelSupplier.java b/src/main/java/com/jozufozu/flywheel/api/ModelSupplier.java deleted file mode 100644 index 9f72f34f5..000000000 --- a/src/main/java/com/jozufozu/flywheel/api/ModelSupplier.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.jozufozu.flywheel.api; - -import javax.annotation.Nonnull; - -import com.jozufozu.flywheel.core.model.Model; - -public interface ModelSupplier { - - @Nonnull - Model get(); -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java index 872335853..72692a955 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java @@ -6,17 +6,17 @@ import java.util.function.Supplier; import com.jozufozu.flywheel.api.InstanceData; import com.jozufozu.flywheel.api.Instancer; -import com.jozufozu.flywheel.core.model.Model; +import com.jozufozu.flywheel.core.ModelSupplier; public abstract class AbstractInstancer implements Instancer { protected final Supplier factory; - protected final Model modelData; + protected final ModelSupplier modelData; protected final ArrayList data = new ArrayList<>(); protected boolean anyToRemove; - protected AbstractInstancer(Supplier factory, Model modelData) { + protected AbstractInstancer(Supplier factory, ModelSupplier modelData) { this.factory = factory; this.modelData = modelData; } @@ -59,7 +59,7 @@ public abstract class AbstractInstancer implements Insta } public int getModelVertexCount() { - return modelData.vertexCount(); + return 0; } public int getInstanceCount() { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/Renderable.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/Renderable.java new file mode 100644 index 000000000..6678847e3 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/Renderable.java @@ -0,0 +1,6 @@ +package com.jozufozu.flywheel.backend.instancing; + +@FunctionalInterface +public interface Renderable { + void draw(); +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterial.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterial.java index 16d997f89..5456c2995 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterial.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterial.java @@ -2,14 +2,12 @@ package com.jozufozu.flywheel.backend.instancing.batching; import java.util.HashMap; import java.util.Map; -import java.util.function.Supplier; import com.jozufozu.flywheel.api.InstanceData; import com.jozufozu.flywheel.api.Instancer; import com.jozufozu.flywheel.api.Material; -import com.jozufozu.flywheel.api.ModelSupplier; import com.jozufozu.flywheel.api.struct.Batched; -import com.jozufozu.flywheel.core.model.Model; +import com.jozufozu.flywheel.core.ModelSupplier; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; @@ -26,7 +24,7 @@ public class BatchedMaterial implements Material { @Override public Instancer model(ModelSupplier modelKey) { - return models.computeIfAbsent(modelKey, k -> new CPUInstancer<>(type, k.get())); + return models.computeIfAbsent(modelKey, k -> new CPUInstancer<>(type, k)); } public void setupAndRenderInto(PoseStack stack, VertexConsumer buffer) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java index d123964e7..ef5d42b67 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java @@ -5,11 +5,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import com.jozufozu.flywheel.api.MaterialGroup; +import com.jozufozu.flywheel.api.InstanceData; import com.jozufozu.flywheel.api.RenderLayer; +import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.backend.instancing.BatchDrawingTracker; import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.TaskEngine; +import com.jozufozu.flywheel.backend.instancing.instancing.InstancedMaterial; import com.jozufozu.flywheel.event.RenderLayerEvent; import com.jozufozu.flywheel.util.FlwUtil; import com.mojang.blaze3d.platform.Lighting; @@ -33,8 +35,8 @@ public class BatchingEngine implements Engine { } @Override - public MaterialGroup state(RenderLayer layer, RenderType type) { - return layers.get(layer).computeIfAbsent(type, BatchedMaterialGroup::new); + public InstancedMaterial material(StructType type) { + return null; } @Override diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java index 828827103..fa47dee00 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java @@ -5,7 +5,7 @@ import com.jozufozu.flywheel.api.struct.Batched; import com.jozufozu.flywheel.backend.instancing.AbstractInstancer; import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.backend.model.DirectVertexConsumer; -import com.jozufozu.flywheel.core.model.Model; +import com.jozufozu.flywheel.core.ModelSupplier; import com.jozufozu.flywheel.core.model.ModelTransformer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; @@ -16,11 +16,11 @@ public class CPUInstancer extends AbstractInstancer { final ModelTransformer sbb; - public CPUInstancer(Batched type, Model modelData) { + public CPUInstancer(Batched type, ModelSupplier modelData) { super(type::create, modelData); batchingType = type; - sbb = new ModelTransformer(modelData); + sbb = new ModelTransformer(modelData.get()); } void submitTasks(PoseStack stack, TaskEngine pool, DirectVertexConsumer consumer) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java index ed4313063..be4f65a71 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java @@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.instancing.blockentity; import com.jozufozu.flywheel.api.Material; import com.jozufozu.flywheel.api.MaterialManager; +import com.jozufozu.flywheel.api.RenderLayer; import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.backend.instancing.AbstractInstance; @@ -11,6 +12,7 @@ import com.jozufozu.flywheel.core.materials.oriented.OrientedData; import com.jozufozu.flywheel.util.box.GridAlignedBB; import com.jozufozu.flywheel.util.box.ImmutableBox; +import net.minecraft.client.renderer.RenderType; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; @@ -77,11 +79,11 @@ public abstract class BlockEntityInstance extends Abstrac } protected Material getTransformMaterial() { - return materialManager.defaultCutout().material(Materials.TRANSFORMED); + return materialManager.material(Materials.TRANSFORMED); } protected Material getOrientedMaterial() { - return materialManager.defaultCutout().material(Materials.ORIENTED); + return materialManager.material(Materials.ORIENTED); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java index 4b469c02f..faff7aff6 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java @@ -1,7 +1,10 @@ package com.jozufozu.flywheel.backend.instancing.instancing; +import java.util.Map; + import org.lwjgl.system.MemoryUtil; +import com.google.common.collect.ImmutableMap; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.InstanceData; import com.jozufozu.flywheel.api.struct.Instanced; @@ -12,10 +15,13 @@ import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer; import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; import com.jozufozu.flywheel.backend.instancing.AbstractInstancer; +import com.jozufozu.flywheel.backend.instancing.Renderable; import com.jozufozu.flywheel.backend.model.BufferedModel; import com.jozufozu.flywheel.backend.model.ModelAllocator; +import com.jozufozu.flywheel.core.ModelSupplier; import com.jozufozu.flywheel.core.layout.BufferLayout; -import com.jozufozu.flywheel.core.model.Model; + +import net.minecraft.client.renderer.RenderType; public class GPUInstancer extends AbstractInstancer { @@ -31,7 +37,7 @@ public class GPUInstancer extends AbstractInstancer { protected boolean anyToUpdate; - public GPUInstancer(Instanced type, Model model) { + public GPUInstancer(Instanced type, ModelSupplier model) { super(type::create, model); this.instanceFormat = type.getLayout(); instancedType = type; @@ -61,14 +67,17 @@ public class GPUInstancer extends AbstractInstancer { return deleted || model == null; } - public void init(ModelAllocator modelAllocator) { - if (isInitialized()) return; + public Map init(ModelAllocator modelAllocator) { + if (isInitialized()) return ImmutableMap.of(); initialized = true; + instanceVBO = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER); + instanceVBO.setGrowthMargin(instanceFormat.getStride() * 16); + vao = new GlVertexArray(); - model = modelAllocator.alloc(modelData, arenaModel -> { + model = modelAllocator.alloc(modelData.get(), arenaModel -> { vao.bind(); arenaModel.setupState(vao); @@ -77,8 +86,7 @@ public class GPUInstancer extends AbstractInstancer { vao.bind(); vao.enableArrays(model.getAttributeCount() + instanceFormat.getAttributeCount()); - instanceVBO = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER); - instanceVBO.setGrowthMargin(instanceFormat.getStride() * 16); + return ImmutableMap.of(modelData.getRenderType(), this::render); } public boolean isInitialized() { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterial.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterial.java index cf7ecfd49..ec3cb2d8a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterial.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterial.java @@ -5,14 +5,18 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Supplier; + +import javax.annotation.Nullable; import com.jozufozu.flywheel.api.InstanceData; import com.jozufozu.flywheel.api.Instancer; import com.jozufozu.flywheel.api.Material; -import com.jozufozu.flywheel.api.ModelSupplier; import com.jozufozu.flywheel.api.struct.Instanced; -import com.jozufozu.flywheel.core.model.Model; +import com.jozufozu.flywheel.backend.instancing.Renderable; +import com.jozufozu.flywheel.backend.model.ModelAllocator; +import com.jozufozu.flywheel.core.ModelSupplier; + +import net.minecraft.client.renderer.RenderType; /** * A collection of Instancers that all have the same format. @@ -22,16 +26,24 @@ public class InstancedMaterial implements Material { protected final Map> models = new HashMap<>(); protected final Instanced type; + + public final Map> renderables = new HashMap<>(); + protected final List> uninitialized = new ArrayList<>(); public InstancedMaterial(Instanced type) { this.type = type; } + @Nullable + public List getRenderables(RenderType type) { + return renderables.get(type); + } + @Override public Instancer model(ModelSupplier modelKey) { return models.computeIfAbsent(modelKey, k -> { - GPUInstancer instancer = new GPUInstancer<>(type, k.get()); + GPUInstancer instancer = new GPUInstancer<>(type, modelKey); uninitialized.add(instancer); return instancer; }); @@ -67,4 +79,18 @@ public class InstancedMaterial implements Material { public Collection> getAllInstancers() { return models.values(); } + + void init(ModelAllocator allocator) { + for (GPUInstancer instancer : uninitialized) { + + instancer.init(allocator) + .forEach(this::addRenderable); + } + uninitialized.clear(); + } + + private void addRenderable(RenderType type, Renderable renderable) { + this.renderables.computeIfAbsent(type, k -> new ArrayList<>()) + .add(renderable); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java index 772259fe2..c483ff678 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java @@ -26,127 +26,24 @@ import net.minecraft.client.renderer.RenderType; * The children of a material group will all be rendered at the same time. * No guarantees are made about the order of draw calls. */ -public class InstancedMaterialGroup

implements MaterialGroup { +public class InstancedMaterialGroup

{ protected final InstancingEngine

owner; protected final RenderType type; - private final Map, InstancedMaterial> materials = new HashMap<>(); - - private ModelAllocator allocator; - private int vertexCount; - private int instanceCount; - public InstancedMaterialGroup(InstancingEngine

owner, RenderType type) { this.owner = owner; this.type = type; } - @SuppressWarnings("unchecked") - @Override - public InstancedMaterial material(StructType type) { - if (type instanceof Instanced instanced) { - return (InstancedMaterial) materials.computeIfAbsent(instanced, InstancedMaterial::new); - } else { - throw new ClassCastException("Cannot use type '" + type + "' with GPU instancing."); - } - } - - /** - * Get the number of instances drawn last frame. - * @return The instance count. - */ - public int getInstanceCount() { - return instanceCount; - } - - /** - * Get the number of vertices drawn last frame. - * @return The vertex count. - */ - public int getVertexCount() { - return vertexCount; - } - public void render(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) { type.setupRenderState(); Textures.bindActiveTextures(); - renderAll(viewProjection, camX, camY, camZ, layer); + //renderAll(viewProjection, camX, camY, camZ, layer); type.clearRenderState(); } - protected void renderAll(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) { - initializeInstancers(); - - vertexCount = 0; - instanceCount = 0; - - for (Map.Entry, InstancedMaterial> entry : materials.entrySet()) { - InstancedMaterial material = entry.getValue(); - if (material.nothingToRender()) continue; - - P program = owner.context.getProgram(ProgramContext.create(entry.getKey() - .getProgramSpec(), Formats.POS_TEX_NORMAL, layer)); - - program.bind(); - program.uploadViewProjection(viewProjection); - program.uploadCameraPos(camX, camY, camZ); - - setup(program); - - for (GPUInstancer instancer : material.getAllInstancers()) { - instancer.render(); - vertexCount += instancer.getVertexCount(); - instanceCount += instancer.getInstanceCount(); - } - } - } - - private void initializeInstancers() { - ModelAllocator allocator = getModelAllocator(); - - // initialize all uninitialized instancers... - for (InstancedMaterial material : materials.values()) { - for (GPUInstancer instancer : material.uninitialized) { - instancer.init(allocator); - } - material.uninitialized.clear(); - } - - if (allocator instanceof ModelPool pool) { - // ...and then flush the model arena in case anything was marked for upload - pool.flush(); - } - } - protected void setup(P program) { } - - public void clear() { - materials.values().forEach(InstancedMaterial::clear); - } - - public void delete() { - materials.values() - .forEach(InstancedMaterial::delete); - - materials.clear(); - } - - private ModelAllocator getModelAllocator() { - if (allocator == null) { - allocator = createAllocator(); - } - return this.allocator; - } - - private static ModelAllocator createAllocator() { - if (GlCompat.getInstance() - .onAMDWindows()) { - return FallbackAllocator.INSTANCE; - } else { - return new ModelPool(Formats.POS_TEX_NORMAL); - } - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java index 04d8e9593..134bd93b4 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java @@ -1,21 +1,27 @@ package com.jozufozu.flywheel.backend.instancing.instancing; -import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Stream; -import javax.annotation.Nullable; +import javax.annotation.Nonnull; -import com.jozufozu.flywheel.api.MaterialGroup; -import com.jozufozu.flywheel.api.RenderLayer; +import com.jozufozu.flywheel.api.InstanceData; +import com.jozufozu.flywheel.api.struct.Instanced; +import com.jozufozu.flywheel.api.struct.StructType; +import com.jozufozu.flywheel.backend.gl.versioned.GlCompat; import com.jozufozu.flywheel.backend.instancing.Engine; +import com.jozufozu.flywheel.backend.instancing.Renderable; import com.jozufozu.flywheel.backend.instancing.TaskEngine; +import com.jozufozu.flywheel.backend.model.FallbackAllocator; +import com.jozufozu.flywheel.backend.model.ModelAllocator; +import com.jozufozu.flywheel.backend.model.ModelPool; +import com.jozufozu.flywheel.core.Formats; import com.jozufozu.flywheel.core.compile.ProgramCompiler; +import com.jozufozu.flywheel.core.compile.ProgramContext; import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.event.RenderLayerEvent; -import com.jozufozu.flywheel.util.FlwUtil; +import com.jozufozu.flywheel.util.Textures; import com.jozufozu.flywheel.util.WeakHashSet; import com.mojang.math.Matrix4f; @@ -34,10 +40,13 @@ public class InstancingEngine

implements Engine { protected final ProgramCompiler

context; protected final GroupFactory

groupFactory; protected final boolean ignoreOriginCoordinate; + private ModelAllocator allocator; - protected final Map>> layers; + private final Map, InstancedMaterial> materials = new HashMap<>(); private final WeakHashSet listeners; + private int vertexCount; + private int instanceCount; public static

Builder

builder(ProgramCompiler

context) { return new Builder<>(context); @@ -49,30 +58,24 @@ public class InstancingEngine

implements Engine { this.listeners = new WeakHashSet<>(); this.groupFactory = groupFactory; + } - this.layers = new EnumMap<>(RenderLayer.class); - for (RenderLayer value : RenderLayer.values()) { - layers.put(value, new HashMap<>()); + @SuppressWarnings("unchecked") + @Nonnull + @Override + public InstancedMaterial material(StructType type) { + if (type instanceof Instanced instanced) { + return (InstancedMaterial) materials.computeIfAbsent(instanced, InstancedMaterial::new); + } else { + throw new ClassCastException("Cannot use type '" + type + "' with GPU instancing."); } } - /** - * Get a material group that will render in the given layer with the given type. - * - * @param layer - * @param type The {@link RenderType} you need to draw with. - * @return A material group whose children will - */ - @Override - public MaterialGroup state(RenderLayer layer, RenderType type) { - return layers.get(layer).computeIfAbsent(type, t -> groupFactory.create(this, t)); - } - - /** - * Render every model for every material. - */ @Override public void render(TaskEngine taskEngine, RenderLayerEvent event) { + + RenderType type = event.getType(); + double camX; double camY; double camZ; @@ -91,28 +94,46 @@ public class InstancingEngine

implements Engine { viewProjection = event.viewProjection; } - getGroupsToRender(event.getLayer()).forEach(group -> group.render(viewProjection, camX, camY, camZ, event.getLayer())); + vertexCount = 0; + instanceCount = 0; + + type.setupRenderState(); + Textures.bindActiveTextures(); + + for (Map.Entry, InstancedMaterial> entry : materials.entrySet()) { + List renderables = entry.getValue() + .getRenderables(type); + + if (renderables == null || renderables.isEmpty()) { + continue; + } + + P program = context.getProgram(ProgramContext.create(entry.getKey() + .getProgramSpec(), Formats.POS_TEX_NORMAL, event.layer)); + + program.bind(); + program.uploadViewProjection(viewProjection); + program.uploadCameraPos(camX, camY, camZ); + + //setup(program); + for (Renderable renderable : renderables) { + renderable.draw(); + } + } + + type.clearRenderState(); } - private Stream> getGroupsToRender(@Nullable RenderLayer layer) { - // layer is null when this is called from CrumblingRenderer - if (layer != null) { - return layers.get(layer) - .values() - .stream(); - } else { - return layers.values() - .stream() - .flatMap(FlwUtil::mapValues); - } + public void clearAll() { + materials.values().forEach(InstancedMaterial::clear); } @Override public void delete() { - for (Map> groups : layers.values()) { + materials.values() + .forEach(InstancedMaterial::delete); - groups.values().forEach(InstancedMaterialGroup::delete); - } + materials.clear(); } @Override @@ -143,22 +164,48 @@ public class InstancingEngine

implements Engine { originCoordinate = new BlockPos(cX, cY, cZ); - for (Map> groups : layers.values()) { - groups.values().forEach(InstancedMaterialGroup::clear); - } + materials.values().forEach(InstancedMaterial::clear); listeners.forEach(OriginShiftListener::onOriginShift); } + + ModelAllocator allocator = getModelAllocator(); + + for (InstancedMaterial material : materials.values()) { + material.init(allocator); + } + + if (allocator instanceof ModelPool pool) { + // ...and then flush the model arena in case anything was marked for upload + pool.flush(); + } + } @Override public void addDebugInfo(List info) { info.add("GL33 Instanced Arrays"); - info.add("Instances: " + getGroupsToRender(null).mapToInt(InstancedMaterialGroup::getInstanceCount).sum()); - info.add("Vertices: " + getGroupsToRender(null).mapToInt(InstancedMaterialGroup::getVertexCount).sum()); + info.add("Instances: " + instanceCount); + info.add("Vertices: " + vertexCount); info.add("Origin: " + originCoordinate.getX() + ", " + originCoordinate.getY() + ", " + originCoordinate.getZ()); } + private ModelAllocator getModelAllocator() { + if (allocator == null) { + allocator = createAllocator(); + } + return this.allocator; + } + + private static ModelAllocator createAllocator() { + if (GlCompat.getInstance() + .onAMDWindows()) { + return FallbackAllocator.INSTANCE; + } else { + return new ModelPool(Formats.POS_TEX_NORMAL); + } + } + @FunctionalInterface public interface OriginShiftListener { void onOriginShift(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java b/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java index 5c1d426c7..c3b9ed6a4 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import org.lwjgl.opengl.GL32; +import org.lwjgl.opengl.GL43; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.vertex.VertexType; diff --git a/src/main/java/com/jozufozu/flywheel/core/ModelSupplier.java b/src/main/java/com/jozufozu/flywheel/core/ModelSupplier.java new file mode 100644 index 000000000..98b59260b --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/ModelSupplier.java @@ -0,0 +1,44 @@ +package com.jozufozu.flywheel.core; + +import javax.annotation.Nonnull; + +import com.jozufozu.flywheel.core.model.Model; +import com.jozufozu.flywheel.util.Lazy; +import com.jozufozu.flywheel.util.NonNullSupplier; + +import net.minecraft.client.renderer.RenderType; + +public class ModelSupplier { + + private final Lazy supplier; + + private RenderType renderType; + + public ModelSupplier(NonNullSupplier supplier) { + this(supplier, RenderType.solid()); + } + + public ModelSupplier(NonNullSupplier supplier, RenderType renderType) { + this.supplier = Lazy.of(supplier); + this.renderType = renderType; + } + + public ModelSupplier setCutout() { + return setRenderType(RenderType.cutoutMipped()); + } + + public ModelSupplier setRenderType(@Nonnull RenderType renderType) { + this.renderType = renderType; + return this; + } + + @Nonnull + public Model get() { + return supplier.get(); + } + + @Nonnull + public RenderType getRenderType() { + return renderType; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/Models.java b/src/main/java/com/jozufozu/flywheel/core/Models.java index a1d52c7ca..e83da4a89 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Models.java +++ b/src/main/java/com/jozufozu/flywheel/core/Models.java @@ -2,12 +2,12 @@ package com.jozufozu.flywheel.core; import java.util.HashMap; import java.util.Map; -import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; -import com.jozufozu.flywheel.api.ModelSupplier; import com.jozufozu.flywheel.core.model.BlockModel; +import com.jozufozu.flywheel.core.model.ModelUtil; +import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.util.Pair; import com.mojang.blaze3d.vertex.PoseStack; @@ -19,19 +19,29 @@ import net.minecraft.world.level.block.state.BlockState; public class Models { public static ModelSupplier block(BlockState state) { - return BLOCK_STATE.apply(state); + return BLOCK_STATE.computeIfAbsent(state, it -> new ModelSupplier(() -> new BlockModel(it))); } public static ModelSupplier partial(PartialModel partial) { - return PARTIAL.apply(partial); + return PARTIAL.computeIfAbsent(partial, it -> new ModelSupplier(() -> new BlockModel(it.get(), Blocks.AIR.defaultBlockState()))); + } + + public static ModelSupplier partial(PartialModel partial, Direction dir) { + return partial(partial, dir, () -> ModelUtil.rotateToFace(dir)); } public static ModelSupplier partial(PartialModel partial, Direction dir, Supplier modelTransform) { - return PARTIAL_DIR.computeIfAbsent(Pair.of(dir, partial), $ -> new SimpleModelSupplier(() -> new BlockModel(partial.get(), Blocks.AIR.defaultBlockState(), modelTransform.get()))); + return PARTIAL_DIR.computeIfAbsent(Pair.of(dir, partial), $ -> new ModelSupplier(() -> new BlockModel(partial.get(), Blocks.AIR.defaultBlockState(), modelTransform.get()))); } - private static final Function BLOCK_STATE = Util.memoize(it -> new SimpleModelSupplier(() -> new BlockModel(it))); - private static final Function PARTIAL = Util.memoize(it -> new SimpleModelSupplier(() -> new BlockModel(it.get(), Blocks.AIR.defaultBlockState()))); + public static void onReload(ReloadRenderersEvent ignored) { + BLOCK_STATE.clear(); + PARTIAL.clear(); + PARTIAL_DIR.clear(); + } + + private static final Map BLOCK_STATE = new HashMap<>(); + private static final Map PARTIAL = new HashMap<>(); private static final Map, ModelSupplier> PARTIAL_DIR = new HashMap<>(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/SimpleModelSupplier.java b/src/main/java/com/jozufozu/flywheel/core/SimpleModelSupplier.java deleted file mode 100644 index 7d0256874..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/SimpleModelSupplier.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.jozufozu.flywheel.core; - -import java.util.function.Supplier; - -import javax.annotation.Nonnull; - -import com.jozufozu.flywheel.api.ModelSupplier; -import com.jozufozu.flywheel.core.model.Model; -import com.jozufozu.flywheel.util.Lazy; -import com.jozufozu.flywheel.util.NonNullSupplier; - -public class SimpleModelSupplier implements ModelSupplier { - - private final Lazy supplier; - - public SimpleModelSupplier(NonNullSupplier supplier) { - this.supplier = Lazy.of(supplier); - } - - @Nonnull - @Override - public Model get() { - return supplier.get(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java index 43d0d7193..742235d67 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java @@ -75,7 +75,7 @@ public class ProgramCompiler

extends Memoizer extends InstancedMateria RenderSystem.setShaderTexture(4, breakingTex); Textures.bindActiveTextures(); - renderAll(viewProjection, camX, camY, camZ, layer); + //renderAll(viewProjection, camX, camY, camZ, layer); CrumblingRenderer._currentLayer.clearRenderState(); } diff --git a/src/main/java/com/jozufozu/flywheel/util/Lazy.java b/src/main/java/com/jozufozu/flywheel/util/Lazy.java index 85963ca10..1913beca0 100644 --- a/src/main/java/com/jozufozu/flywheel/util/Lazy.java +++ b/src/main/java/com/jozufozu/flywheel/util/Lazy.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.util; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; import javax.annotation.Nonnull; @@ -24,6 +25,10 @@ public class Lazy implements Supplier { return value; } + public Lazy map(Function func) { + return new Lazy<>(() -> func.apply(get())); + } + public static Lazy of(NonNullSupplier factory) { return new Lazy<>(factory); } diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java index c0d2f95a0..415feec67 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java @@ -3,24 +3,24 @@ package com.jozufozu.flywheel.vanilla; import javax.annotation.Nonnull; import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.ModelSupplier; import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import com.jozufozu.flywheel.core.Materials; -import com.jozufozu.flywheel.core.SimpleModelSupplier; +import com.jozufozu.flywheel.core.ModelSupplier; import com.jozufozu.flywheel.core.hardcoded.ModelPart; import com.jozufozu.flywheel.core.materials.oriented.OrientedData; import com.jozufozu.flywheel.util.AnimationTickHolder; import com.mojang.math.Quaternion; import com.mojang.math.Vector3f; +import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.blockentity.BellRenderer; import net.minecraft.util.Mth; import net.minecraft.world.level.block.entity.BellBlockEntity; public class BellInstance extends BlockEntityInstance implements DynamicInstance { - private static final ModelSupplier MODEL = new SimpleModelSupplier(BellInstance::createBellModel); + private static final ModelSupplier MODEL = new ModelSupplier(BellInstance::createBellModel, RenderType.cutoutMipped()); private final OrientedData bell; @@ -63,8 +63,7 @@ public class BellInstance extends BlockEntityInstance implement } private OrientedData createBellInstance() { - return materialManager.defaultCutout() - .material(Materials.ORIENTED) + return materialManager.material(Materials.ORIENTED) .model(MODEL) .createInstance(); } diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java index 79aa0cf5e..ada245864 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java @@ -6,11 +6,10 @@ import java.util.function.BiFunction; import javax.annotation.Nonnull; import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.ModelSupplier; import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import com.jozufozu.flywheel.core.Materials; -import com.jozufozu.flywheel.core.SimpleModelSupplier; +import com.jozufozu.flywheel.core.ModelSupplier; import com.jozufozu.flywheel.core.hardcoded.ModelPart; import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.core.materials.oriented.OrientedData; @@ -35,8 +34,8 @@ import net.minecraft.world.level.block.state.properties.ChestType; public class ChestInstance extends BlockEntityInstance implements DynamicInstance { - private static final BiFunction LID = Util.memoize((type, sprite) -> new SimpleModelSupplier(() -> createLidModel(type, sprite))); - private static final BiFunction BASE = Util.memoize((type, sprite) -> new SimpleModelSupplier(() -> createBaseModel(type, sprite))); + private static final BiFunction LID = Util.memoize((type, mat) -> new ModelSupplier(() -> createLidModel(type, mat.sprite()), RenderType.entitySolid(mat.atlasLocation()))); + private static final BiFunction BASE = Util.memoize((type, mat) -> new ModelSupplier(() -> createBaseModel(type, mat.sprite()), RenderType.entitySolid(mat.atlasLocation()))); private final OrientedData body; private final ModelData lid; @@ -117,17 +116,15 @@ public class ChestInstance extends Block private OrientedData baseInstance() { - return materialManager.solid(RenderType.entitySolid(renderMaterial.atlasLocation())) - .material(Materials.ORIENTED) - .model(BASE.apply(chestType, renderMaterial.sprite())) + return materialManager.material(Materials.ORIENTED) + .model(BASE.apply(chestType, renderMaterial)) .createInstance(); } private ModelData lidInstance() { - return materialManager.solid(RenderType.entitySolid(renderMaterial.atlasLocation())) - .material(Materials.TRANSFORMED) - .model(LID.apply(chestType, renderMaterial.sprite())) + return materialManager.material(Materials.TRANSFORMED) + .model(LID.apply(chestType, renderMaterial)) .createInstance(); } diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java index 30f66daf0..3111a8844 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java @@ -2,13 +2,14 @@ package com.jozufozu.flywheel.vanilla; import javax.annotation.Nonnull; +import com.jozufozu.flywheel.api.Material; import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.ModelSupplier; import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.backend.instancing.entity.EntityInstance; import com.jozufozu.flywheel.core.Materials; -import com.jozufozu.flywheel.core.SimpleModelSupplier; +import com.jozufozu.flywheel.core.ModelSupplier; +import com.jozufozu.flywheel.core.Models; import com.jozufozu.flywheel.core.hardcoded.ModelPart; import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.core.model.Model; @@ -29,7 +30,7 @@ import net.minecraft.world.phys.Vec3; public class MinecartInstance extends EntityInstance implements DynamicInstance, TickableInstance { private static final ResourceLocation MINECART_LOCATION = new ResourceLocation("textures/entity/minecart.png"); - private static final ModelSupplier MODEL = new SimpleModelSupplier(MinecartInstance::getBodyModel); + private static final ModelSupplier MODEL = new ModelSupplier(MinecartInstance::getBodyModel, RenderType.entitySolid(MINECART_LOCATION)); private final PoseStack stack = new PoseStack(); @@ -147,15 +148,13 @@ public class MinecartInstance extends EntityInstance if (blockstate.getRenderShape() == RenderShape.INVISIBLE) return null; - return materialManager.defaultSolid() - .material(Materials.TRANSFORMED) - .getModel(blockstate) + return materialManager.material(Materials.TRANSFORMED) + .model(Models.block(blockstate)) .createInstance(); } private ModelData getBody() { - return materialManager.solid(RenderType.entitySolid(MINECART_LOCATION)) - .material(Materials.TRANSFORMED) + return materialManager.material(Materials.TRANSFORMED) .model(MODEL) .createInstance(); } diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java index 95a69b5bc..833f1acd5 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java @@ -3,11 +3,10 @@ package com.jozufozu.flywheel.vanilla; import java.util.function.Function; import com.jozufozu.flywheel.api.MaterialManager; -import com.jozufozu.flywheel.api.ModelSupplier; import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import com.jozufozu.flywheel.core.Materials; -import com.jozufozu.flywheel.core.SimpleModelSupplier; +import com.jozufozu.flywheel.core.ModelSupplier; import com.jozufozu.flywheel.core.hardcoded.ModelPart; import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.util.AnimationTickHolder; @@ -27,8 +26,8 @@ import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; public class ShulkerBoxInstance extends BlockEntityInstance implements DynamicInstance { - private static final Function BASE = Util.memoize(it -> new SimpleModelSupplier(() -> makeBaseModel(it))); - private static final Function LID = Util.memoize(it -> new SimpleModelSupplier(() -> makeLidModel(it))); + private static final Function BASE = Util.memoize(it -> new ModelSupplier(() -> makeBaseModel(it), RenderType.entityCutoutNoCull(Sheets.SHULKER_SHEET))); + private static final Function LID = Util.memoize(it -> new ModelSupplier(() -> makeLidModel(it), RenderType.entityCutoutNoCull(Sheets.SHULKER_SHEET))); private final TextureAtlasSprite texture; @@ -74,9 +73,8 @@ public class ShulkerBoxInstance extends BlockEntityInstance