Merge remote-tracking branch 'origin/1.18/dev' into 1.18/fabric/dev

Conflicts:
	gradle.properties
	src/main/java/com/jozufozu/flywheel/Flywheel.java
	src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java
	src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java
	src/main/java/com/jozufozu/flywheel/config/BooleanConfigCommand.java
	src/main/java/com/jozufozu/flywheel/config/BooleanDirective.java
	src/main/java/com/jozufozu/flywheel/config/EngineArgument.java
	src/main/java/com/jozufozu/flywheel/config/FlwCommands.java
	src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java
	src/main/resources/META-INF/mods.toml
This commit is contained in:
PepperCode1 2022-01-31 18:18:24 -08:00
commit c38d66e867
24 changed files with 214 additions and 29 deletions

13
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,13 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: Jozufozu
open_collective: # Replace with a single Open Collective username
ko_fi: Jozufozu
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View file

@ -59,6 +59,7 @@ body:
label: Mod Version label: Mod Version
description: The version of the mod you were using when the bug occured description: The version of the mod you were using when the bug occured
options: options:
- "0.6.0"
- "0.5.1" - "0.5.1"
- "0.5.0a" - "0.5.0a"
- "0.5.0" - "0.5.0"

View file

@ -1,3 +1,15 @@
0.6.0:
With this release, Flywheel is no longer needed on servers! Forge finally has client commands,
and the /flywheel command now takes advantage of this.
Fixes
- Fix crash when running with sodium/magnesium.
Technical/API
- Backend is now a static class.
- Shaders are now compiled on-the-fly and cached.
- Significantly reduced the amount of boilerplate needed in instancing shaders.
- Struct types no longer need to be registered ahead of time.
- Simplify unnecessarily complicated game state system.
0.5.1: 0.5.1:
Fixes Fixes
- Fix crash on resource reload with backend off - Fix crash on resource reload with backend off

View file

@ -6,12 +6,12 @@ mod_version = 0.6.0
mc_update_version = 1.18 mc_update_version = 1.18
minecraft_version = 1.18.1 minecraft_version = 1.18.1
loader_version = 0.12.12 loader_version = 0.12.12
fabric_version = 0.45.0+1.18 fabric_version = 0.46.1+1.18
# build dependency versions # build dependency versions
loom_version = 0.10-SNAPSHOT loom_version = 0.10-SNAPSHOT
cursegradle_version = 1.4.0 cursegradle_version = 1.4.0
parchment_version = 2021.12.19 parchment_version = 2022.01.23
# curseforge info # curseforge info
projectId = 486392 projectId = 486392

View file

@ -3,12 +3,28 @@ package com.jozufozu.flywheel;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.SemanticVersion;
import net.fabricmc.loader.api.Version;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
public class Flywheel { public class Flywheel {
public static final String ID = "flywheel"; public static final String ID = "flywheel";
public static final Logger LOGGER = LogManager.getLogger(Flywheel.class); public static final Logger LOGGER = LogManager.getLogger(Flywheel.class);
public static SemanticVersion VERSION;
static void initVersion() {
Version version = FabricLoader.getInstance()
.getModContainer(ID)
.orElseThrow(() -> new IllegalStateException("Could not get the mod container for Flywheel!"))
.getMetadata()
.getVersion();
if (!(version instanceof SemanticVersion semver)) {
throw new IllegalStateException("Got non-semantic version for Flywheel!");
}
VERSION = semver;
}
public static ResourceLocation rl(String path) { public static ResourceLocation rl(String path) {
return new ResourceLocation(ID, path); return new ResourceLocation(ID, path);

View file

@ -28,6 +28,8 @@ public class FlywheelClient implements ClientModInitializer {
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
Flywheel.initVersion();
Backend.init(); Backend.init();
FlywheelEvents.GATHER_CONTEXT.register(Contexts::flwInit); FlywheelEvents.GATHER_CONTEXT.register(Contexts::flwInit);

View file

@ -25,6 +25,10 @@ public class Backend {
private static final Loader loader = new Loader(); private static final Loader loader = new Loader();
public static FlwEngine getEngine() {
return engine;
}
/** /**
* Get a string describing the Flywheel backend. When there are eventually multiple backends * Get a string describing the Flywheel backend. When there are eventually multiple backends
* (Meshlet, MDI, GL31 Draw Instanced are planned), this will name which one is in use. * (Meshlet, MDI, GL31 Draw Instanced are planned), this will name which one is in use.
@ -33,10 +37,6 @@ public class Backend {
return engine == null ? "" : engine.getProperName(); return engine == null ? "" : engine.getProperName();
} }
public static FlwEngine getEngine() {
return engine;
}
@Nullable @Nullable
public static ProgramSpec getSpec(ResourceLocation name) { public static ProgramSpec getSpec(ResourceLocation name) {
return loader.get(name); return loader.get(name);

View file

@ -62,12 +62,12 @@ public abstract class AbstractInstancer<D extends InstanceData> implements Insta
return modelData.vertexCount(); return modelData.vertexCount();
} }
public int numInstances() { public int getInstanceCount() {
return data.size(); return data.size();
} }
public int getTotalVertexCount() { public int getVertexCount() {
return getModelVertexCount() * numInstances(); return getModelVertexCount() * getInstanceCount();
} }
protected void removeDeletedInstances() { protected void removeDeletedInstances() {

View file

@ -1,6 +1,9 @@
package com.jozufozu.flywheel.backend.instancing; package com.jozufozu.flywheel.backend.instancing;
import java.util.List;
import com.jozufozu.flywheel.api.MaterialManager; import com.jozufozu.flywheel.api.MaterialManager;
public interface Engine extends RenderDispatcher, MaterialManager { public interface Engine extends RenderDispatcher, MaterialManager {
void addDebugInfo(List<String> info);
} }

View file

@ -46,6 +46,15 @@ public abstract class InstanceManager<T> implements InstancingEngine.OriginShift
this.tickableInstances = new Object2ObjectOpenHashMap<>(); this.tickableInstances = new Object2ObjectOpenHashMap<>();
} }
/**
* Get the number of game objects that are currently being instanced.
*
* @return The object count.
*/
public int getObjectCount() {
return instances.size();
}
/** /**
* Is the given object capable of being instanced at all? * Is the given object capable of being instanced at all?
* *

View file

@ -1,5 +1,8 @@
package com.jozufozu.flywheel.backend.instancing; package com.jozufozu.flywheel.backend.instancing;
import java.util.List;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.Backend;
@ -74,7 +77,7 @@ public class InstanceWorld {
* Free all acquired resources and invalidate this instance world. * Free all acquired resources and invalidate this instance world.
*/ */
public void delete() { public void delete() {
this.taskEngine.stopWorkers(); taskEngine.stopWorkers();
engine.delete(); engine.delete();
entityInstanceManager.detachLightListeners(); entityInstanceManager.detachLightListeners();
blockEntityInstanceManager.detachLightListeners(); blockEntityInstanceManager.detachLightListeners();
@ -133,4 +136,11 @@ public class InstanceWorld {
world.entitiesForRendering() world.entitiesForRendering()
.forEach(entityInstanceManager::add); .forEach(entityInstanceManager::add);
} }
public void getDebugString(List<String> debug) {
debug.add("");
debug.add("Flywheel: " + Flywheel.VERSION);
debug.add("B: " + blockEntityInstanceManager.getObjectCount() + ", E: " + entityInstanceManager.getObjectCount());
engine.addDebugInfo(debug);
}
} }

View file

@ -1,5 +1,7 @@
package com.jozufozu.flywheel.backend.instancing; package com.jozufozu.flywheel.backend.instancing;
import java.util.List;
import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.event.BeginFrameEvent;
import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.event.ReloadRenderersEvent;
@ -101,4 +103,8 @@ public class InstancedRenderDispatcher {
.loadEntities(world); .loadEntities(world);
} }
public static void getDebugString(List<String> debug) {
instanceWorlds.get(Minecraft.getInstance().level)
.getDebugString(debug);
}
} }

View file

@ -20,6 +20,8 @@ public class BatchedMaterialGroup implements MaterialGroup {
protected final RenderType state; protected final RenderType state;
private final Map<Batched<? extends InstanceData>, BatchedMaterial<?>> materials = new HashMap<>(); private final Map<Batched<? extends InstanceData>, BatchedMaterial<?>> materials = new HashMap<>();
private int vertexCount;
private int instanceCount;
public BatchedMaterialGroup(RenderType state) { public BatchedMaterialGroup(RenderType state) {
this.state = state; this.state = state;
@ -37,11 +39,13 @@ public class BatchedMaterialGroup implements MaterialGroup {
public void render(PoseStack stack, BatchDrawingTracker source, TaskEngine pool) { public void render(PoseStack stack, BatchDrawingTracker source, TaskEngine pool) {
int vertexCount = 0; vertexCount = 0;
instanceCount = 0;
for (BatchedMaterial<?> material : materials.values()) { for (BatchedMaterial<?> material : materials.values()) {
for (CPUInstancer<?> instancer : material.models.values()) { for (CPUInstancer<?> instancer : material.models.values()) {
instancer.setup(); instancer.setup();
vertexCount += instancer.getTotalVertexCount(); vertexCount += instancer.getVertexCount();
instanceCount += instancer.getInstanceCount();
} }
} }
@ -65,4 +69,20 @@ public class BatchedMaterialGroup implements MaterialGroup {
public void delete() { public void delete() {
materials.clear(); materials.clear();
} }
/**
* 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;
}
} }

View file

@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.instancing.batching;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import com.jozufozu.flywheel.api.MaterialGroup; import com.jozufozu.flywheel.api.MaterialGroup;
@ -10,6 +11,7 @@ import com.jozufozu.flywheel.backend.instancing.BatchDrawingTracker;
import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.Engine;
import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.event.RenderLayerEvent; import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.jozufozu.flywheel.util.FlwUtil;
import com.mojang.blaze3d.platform.Lighting; import com.mojang.blaze3d.platform.Lighting;
import com.mojang.math.Matrix4f; import com.mojang.math.Matrix4f;
@ -28,7 +30,6 @@ public class BatchingEngine implements Engine {
for (RenderLayer value : RenderLayer.values()) { for (RenderLayer value : RenderLayer.values()) {
layers.put(value, new HashMap<>()); layers.put(value, new HashMap<>());
} }
} }
@Override @Override
@ -70,4 +71,18 @@ public class BatchingEngine implements Engine {
} }
@Override
public void addDebugInfo(List<String> info) {
info.add("Batching");
info.add("Instances: " + layers.values()
.stream()
.flatMap(FlwUtil::mapValues)
.mapToInt(BatchedMaterialGroup::getInstanceCount)
.sum());
info.add("Vertices: " + layers.values()
.stream()
.flatMap(FlwUtil::mapValues)
.mapToInt(BatchedMaterialGroup::getVertexCount)
.sum());
}
} }

View file

@ -24,7 +24,7 @@ public class CPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
} }
void submitTasks(PoseStack stack, TaskEngine pool, DirectVertexConsumer consumer) { void submitTasks(PoseStack stack, TaskEngine pool, DirectVertexConsumer consumer) {
int instances = numInstances(); int instances = getInstanceCount();
while (instances > 0) { while (instances > 0) {
int end = instances; int end = instances;

View file

@ -46,6 +46,14 @@ public class InstancedMaterial<D extends InstanceData> implements Material<D> {
}); });
} }
public int getInstanceCount() {
return models.values().stream().mapToInt(GPUInstancer::getInstanceCount).sum();
}
public int getVertexCount() {
return models.values().stream().mapToInt(GPUInstancer::getVertexCount).sum();
}
public boolean nothingToRender() { public boolean nothingToRender() {
return models.size() > 0 && models.values() return models.size() > 0 && models.values()
.stream() .stream()

View file

@ -34,6 +34,9 @@ public class InstancedMaterialGroup<P extends WorldProgram> implements MaterialG
private final Map<Instanced<? extends InstanceData>, InstancedMaterial<?>> materials = new HashMap<>(); private final Map<Instanced<? extends InstanceData>, InstancedMaterial<?>> materials = new HashMap<>();
private final ModelAllocator allocator; private final ModelAllocator allocator;
private int vertexCount;
private int instanceCount;
public InstancedMaterialGroup(InstancingEngine<P> owner, RenderType type) { public InstancedMaterialGroup(InstancingEngine<P> owner, RenderType type) {
this.owner = owner; this.owner = owner;
this.type = type; this.type = type;
@ -54,6 +57,22 @@ public class InstancedMaterialGroup<P extends WorldProgram> implements MaterialG
} }
} }
/**
* 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) { public void render(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) {
type.setupRenderState(); type.setupRenderState();
Textures.bindActiveTextures(); Textures.bindActiveTextures();
@ -75,6 +94,9 @@ public class InstancedMaterialGroup<P extends WorldProgram> implements MaterialG
pool.flush(); pool.flush();
} }
vertexCount = 0;
instanceCount = 0;
for (Map.Entry<Instanced<? extends InstanceData>, InstancedMaterial<?>> entry : materials.entrySet()) { for (Map.Entry<Instanced<? extends InstanceData>, InstancedMaterial<?>> entry : materials.entrySet()) {
InstancedMaterial<?> material = entry.getValue(); InstancedMaterial<?> material = entry.getValue();
if (material.nothingToRender()) continue; if (material.nothingToRender()) continue;
@ -90,6 +112,8 @@ public class InstancedMaterialGroup<P extends WorldProgram> implements MaterialG
for (GPUInstancer<?> instancer : material.getAllInstancers()) { for (GPUInstancer<?> instancer : material.getAllInstancers()) {
instancer.render(); instancer.render();
vertexCount += instancer.getVertexCount();
instanceCount += instancer.getInstanceCount();
} }
} }
} }

View file

@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.instancing.instancing;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -15,6 +16,7 @@ import com.jozufozu.flywheel.core.compile.ProgramCompiler;
import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.core.shader.WorldProgram;
import com.jozufozu.flywheel.event.RenderLayerEvent; import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.jozufozu.flywheel.fabric.helper.Matrix4fHelper; import com.jozufozu.flywheel.fabric.helper.Matrix4fHelper;
import com.jozufozu.flywheel.util.FlwUtil;
import com.jozufozu.flywheel.util.WeakHashSet; import com.jozufozu.flywheel.util.WeakHashSet;
import com.mojang.math.Matrix4f; import com.mojang.math.Matrix4f;
@ -102,8 +104,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
} else { } else {
return layers.values() return layers.values()
.stream() .stream()
.flatMap(it -> it.values() .flatMap(FlwUtil::mapValues);
.stream());
} }
} }
@ -151,6 +152,14 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
} }
} }
@Override
public void addDebugInfo(List<String> info) {
info.add("GL33 Instanced Arrays");
info.add("Origin: " + originCoordinate.getX() + ", " + originCoordinate.getY() + ", " + originCoordinate.getZ());
info.add("Instances: " + getGroupsToRender(null).mapToInt(InstancedMaterialGroup::getInstanceCount).sum());
info.add("Vertices: " + getGroupsToRender(null).mapToInt(InstancedMaterialGroup::getVertexCount).sum());
}
@FunctionalInterface @FunctionalInterface
public interface OriginShiftListener { public interface OriginShiftListener {
void onOriginShift(); void onOriginShift();

View file

@ -3,6 +3,7 @@ package com.jozufozu.flywheel.event;
import java.util.List; import java.util.List;
import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.light.LightUpdater; import com.jozufozu.flywheel.light.LightUpdater;
import com.jozufozu.flywheel.util.WorldAttached; import com.jozufozu.flywheel.util.WorldAttached;
@ -11,16 +12,9 @@ import net.minecraft.client.multiplayer.ClientLevel;
public class ForgeEvents { public class ForgeEvents {
public static void addToDebugScreen(List<String> right) { public static void addToDebugScreen(List<String> left) {
String text = "Flywheel: " + Backend.getBackendDescriptor(); InstancedRenderDispatcher.getDebugString(left);
if (right.size() < 10) {
right.add("");
right.add(text);
} else {
right.add(9, "");
right.add(10, text);
}
} }
public static void unloadWorld(ClientLevel world) { public static void unloadWorld(ClientLevel world) {

View file

@ -14,8 +14,8 @@ import net.minecraft.client.gui.components.DebugScreenOverlay;
@Mixin(DebugScreenOverlay.class) @Mixin(DebugScreenOverlay.class)
public abstract class DebugScreenOverlayMixin extends GuiComponent { public abstract class DebugScreenOverlayMixin extends GuiComponent {
@Inject(method = "getSystemInformation", at = @At("RETURN")) @Inject(method = "getGameInformation", at = @At("RETURN"))
private void modifyRightText(CallbackInfoReturnable<List<String>> cir) { private void modifyLeftText(CallbackInfoReturnable<List<String>> cir) {
ForgeEvents.addToDebugScreen(cir.getReturnValue()); ForgeEvents.addToDebugScreen(cir.getReturnValue());
} }
} }

View file

@ -0,0 +1,16 @@
package com.jozufozu.flywheel.mixin;
import java.util.Map;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.world.level.block.entity.BlockEntityType;
@Mixin(BlockEntityRenderDispatcher.class)
public interface BlockEntityRenderDispatcherAccessor {
@Accessor("renderers")
Map<BlockEntityType<?>, BlockEntityRenderer<?>> flywheel$getRenderers();
}

View file

@ -1,9 +1,26 @@
package com.jozufozu.flywheel.util; package com.jozufozu.flywheel.util;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map;
import java.util.stream.Stream;
import com.jozufozu.flywheel.mixin.BlockEntityRenderDispatcherAccessor;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.world.level.block.entity.BlockEntityType;
public class FlwUtil { public class FlwUtil {
/**
* Get the (effectively global) map of BlockEntityTypes to Renderers.
* @return An immutable map of BlockEntityTypes to BlockEntityRenderers.
*/
public static Map<BlockEntityType<?>, BlockEntityRenderer<?>> getBlockEntityRenderers() {
Minecraft mc = Minecraft.getInstance();
return ((BlockEntityRenderDispatcherAccessor) mc.getBlockEntityRenderDispatcher()).flywheel$getRenderers();
}
public static String repeatChar(char c, int n) { public static String repeatChar(char c, int n) {
char[] arr = new char[n]; char[] arr = new char[n];
@ -52,4 +69,8 @@ public class FlwUtil {
} }
} }
} }
public static <R> Stream<R> mapValues(Map<?, R> map) {
return map.values().stream();
}
} }

View file

@ -56,8 +56,13 @@ public interface Translate<Self> {
return translate(-vec.getX(), -vec.getY(), -vec.getZ()); return translate(-vec.getX(), -vec.getY(), -vec.getZ());
} }
default Self nudge(int id) { /**
long randomBits = (long) id * 31L * 493286711L; * Translates this object randomly by a very small amount.
* @param seed The seed to use to generate the random offsets.
* @return {@code this}
*/
default Self nudge(int seed) {
long randomBits = (long) seed * 31L * 493286711L;
randomBits = randomBits * randomBits * 4392167121L + randomBits * 98761L; randomBits = randomBits * randomBits * 4392167121L + randomBits * 98761L;
float xNudge = (((float) (randomBits >> 16 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F; float xNudge = (((float) (randomBits >> 16 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F;
float yNudge = (((float) (randomBits >> 20 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F; float yNudge = (((float) (randomBits >> 20 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F;

View file

@ -4,6 +4,7 @@
"package": "com.jozufozu.flywheel.mixin", "package": "com.jozufozu.flywheel.mixin",
"compatibilityLevel": "JAVA_17", "compatibilityLevel": "JAVA_17",
"client": [ "client": [
"BlockEntityRenderDispatcherAccessor",
"BlockEntityTypeMixin", "BlockEntityTypeMixin",
"BufferBuilderMixin", "BufferBuilderMixin",
"BufferUploaderMixin", "BufferUploaderMixin",