diff --git a/README.md b/README.md index db3237998..da4adb9c1 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,7 @@ This work, "PolyPatcher", is adapted from ["Patcher"](https://sk1er.club/mods/pa - Boost performance by reducing quad counts in item models - Boost performance by decreasing size of sine and cosine lookup tables - Boost performance by only rendering special tile entities once instead of twice per frame +- Boost performance by optimizing adding normals to vertex formats - Boost performance by unloading tile entities quickly - Improve speed when changing language, mipmap level, and anisotropic filtering level - Fix Forge held item lighting to match vanilla diff --git a/src/main/java/club/sk1er/patcher/hooks/VertexLighterFlatHook.java b/src/main/java/club/sk1er/patcher/hooks/VertexLighterFlatHook.java new file mode 100644 index 000000000..10d97e250 --- /dev/null +++ b/src/main/java/club/sk1er/patcher/hooks/VertexLighterFlatHook.java @@ -0,0 +1,20 @@ +package club.sk1er.patcher.hooks; + +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.client.renderer.vertex.VertexFormatElement; + +public class VertexLighterFlatHook { + private static final VertexFormatElement NORMAL_4F = new VertexFormatElement(0, VertexFormatElement.EnumType.FLOAT, VertexFormatElement.EnumUsage.NORMAL, 4); + private static final VertexFormat BLOCK_WITH_NORMAL = withNormalUncached(DefaultVertexFormats.BLOCK); + + public static VertexFormat withNormal(VertexFormat format) { + if (format == DefaultVertexFormats.BLOCK) return BLOCK_WITH_NORMAL; + return withNormalUncached(format); + } + + private static VertexFormat withNormalUncached(VertexFormat format) { + if (format == null || format.hasNormal()) return format; + return new VertexFormat(format).addElement(NORMAL_4F); + } +} diff --git a/src/main/java/club/sk1er/patcher/hooks/accessors/IVertexLighterFlat.java b/src/main/java/club/sk1er/patcher/hooks/accessors/IVertexLighterFlat.java index aaff8cf34..40f2e43e8 100644 --- a/src/main/java/club/sk1er/patcher/hooks/accessors/IVertexLighterFlat.java +++ b/src/main/java/club/sk1er/patcher/hooks/accessors/IVertexLighterFlat.java @@ -5,4 +5,6 @@ @SuppressWarnings("unused") public interface IVertexLighterFlat { BlockInfo getBlockInfo(); + + void resetBlockInfo(); } diff --git a/src/main/java/club/sk1er/patcher/mixins/performance/forge/LightUtilMixin_OptimizeNormals.java b/src/main/java/club/sk1er/patcher/mixins/performance/forge/LightUtilMixin_OptimizeNormals.java new file mode 100644 index 000000000..665f646d9 --- /dev/null +++ b/src/main/java/club/sk1er/patcher/mixins/performance/forge/LightUtilMixin_OptimizeNormals.java @@ -0,0 +1,78 @@ +package club.sk1er.patcher.mixins.performance.forge; + +import club.sk1er.patcher.hooks.VertexLighterFlatHook; +import com.google.common.cache.LoadingCache; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.client.renderer.vertex.VertexFormatElement; +import net.minecraftforge.client.model.pipeline.LightUtil; +import org.apache.commons.lang3.tuple.Pair; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static net.minecraftforge.client.model.pipeline.LightUtil.mapFormats; + +@Mixin(value = LightUtil.class, remap = false) +public abstract class LightUtilMixin_OptimizeNormals { + //#if MC==10809 + @Unique + private static final ConcurrentMap, int[]> patcher$FORMAT_MAPS = new ConcurrentHashMap<>(); + @Unique + private static final VertexFormat patcher$DEFAULT_FROM = VertexLighterFlatHook.withNormal(DefaultVertexFormats.BLOCK); + @Unique + private static final VertexFormat patcher$DEFAULT_TO = DefaultVertexFormats.ITEM; + @Unique + private static final int[] patcher$DEFAULT_MAPPING = patcher$generateMapping(patcher$DEFAULT_FROM, patcher$DEFAULT_TO); + + @SuppressWarnings("UnstableApiUsage") + @Redirect(method = "putBakedQuad", at = @At(value = "INVOKE", target = "Lcom/google/common/cache/LoadingCache;getUnchecked(Ljava/lang/Object;)Ljava/lang/Object;")) + private static V patcher$getUnchecked(LoadingCache instance, K k) { + return (V) mapFormats((VertexFormat) k, DefaultVertexFormats.ITEM); + } + +// @Inject(method = "mapFormats", at = @At("HEAD"), cancellable = true) +// private static void patcher$fasterMapFormats(VertexFormat from, VertexFormat to, CallbackInfoReturnable cir) { +// if (from.equals(patcher$DEFAULT_FROM) && to.equals(patcher$DEFAULT_TO)) { +// cir.setReturnValue(patcher$DEFAULT_MAPPING); +// return; +// } +// cir.setReturnValue(patcher$FORMAT_MAPS.computeIfAbsent(Pair.of(from, to), pair -> patcher$generateMapping(pair.getLeft(), pair.getRight()))); +// } + + /** + * @author MicrocontrollersDev + * @reason the above inject doesnt work + */ + @Overwrite + public static int[] mapFormats(VertexFormat from, VertexFormat to) { + if (from.equals(patcher$DEFAULT_FROM) && to.equals(patcher$DEFAULT_TO)) return patcher$DEFAULT_MAPPING; + return patcher$FORMAT_MAPS.computeIfAbsent(Pair.of(from, to), pair -> patcher$generateMapping(pair.getLeft(), pair.getRight())); + } + + @Unique + private static int[] patcher$generateMapping(VertexFormat from, VertexFormat to) { + int fromCount = from.getElementCount(); + int toCount = to.getElementCount(); + int[] eMap = new int[fromCount]; + + for(int e = 0; e < fromCount; e++) { + VertexFormatElement expected = from.getElement(e); + int e2; + for(e2 = 0; e2 < toCount; e2++) { + VertexFormatElement current = to.getElement(e2); + if(expected.getUsage() == current.getUsage() && expected.getIndex() == current.getIndex()) { + break; + } + } + eMap[e] = e2; + } + return eMap; + } + //#endif +} diff --git a/src/main/java/club/sk1er/patcher/mixins/performance/forge/VertexLighterFlatMixin_OptimizeNormals.java b/src/main/java/club/sk1er/patcher/mixins/performance/forge/VertexLighterFlatMixin_OptimizeNormals.java new file mode 100644 index 000000000..c660c502e --- /dev/null +++ b/src/main/java/club/sk1er/patcher/mixins/performance/forge/VertexLighterFlatMixin_OptimizeNormals.java @@ -0,0 +1,74 @@ +package club.sk1er.patcher.mixins.performance.forge; + +import club.sk1er.patcher.hooks.VertexLighterFlatHook; +import club.sk1er.patcher.hooks.accessors.IVertexLighterFlat; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraftforge.client.model.pipeline.IVertexConsumer; +import net.minecraftforge.client.model.pipeline.QuadGatheringTransformer; +import net.minecraftforge.client.model.pipeline.VertexLighterFlat; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Objects; + +@Mixin(value = VertexLighterFlat.class, remap = false) +public abstract class VertexLighterFlatMixin_OptimizeNormals extends QuadGatheringTransformer implements IVertexLighterFlat { + //#if MC==10809 + @Unique + protected VertexFormat patcher$baseFormat; + @Shadow + protected int posIndex; + @Shadow + protected int normalIndex; + @Shadow + protected int colorIndex; + @Shadow + protected int lightmapIndex; + + @Inject(method = "setParent", at = @At("HEAD"), cancellable = true) + private void patcher$optimizeSetParent(IVertexConsumer parent, CallbackInfo ci) { + super.setParent(parent); + setVertexFormat(parent.getVertexFormat()); + ci.cancel(); + } + + @Override + public void setVertexFormat(VertexFormat format) { + if (Objects.equals(format,patcher$baseFormat)) return; + this.patcher$baseFormat = format; + super.setVertexFormat(VertexLighterFlatHook.withNormal(format)); + for (int i = 0; i < getVertexFormat().getElementCount(); i++) { + switch (getVertexFormat().getElement(i).getUsage()) { + case POSITION: + posIndex = i; + break; + case NORMAL: + normalIndex = i; + break; + case COLOR: + colorIndex = i; + break; + case UV: + if (getVertexFormat().getElement(i).getIndex() == 1) { + lightmapIndex = i; + } + break; + default: + } + } + if (posIndex == -1) { + throw new IllegalArgumentException("vertex lighter needs format with position"); + } + if (lightmapIndex == -1) { + throw new IllegalArgumentException("vertex lighter needs format with lightmap"); + } + if (colorIndex == -1) { + throw new IllegalArgumentException("vertex lighter needs format with color"); + } + } + //#endif +} diff --git a/src/main/resources/mixins.patcher.json b/src/main/resources/mixins.patcher.json index 5536ad057..3e1302951 100644 --- a/src/main/resources/mixins.patcher.json +++ b/src/main/resources/mixins.patcher.json @@ -263,8 +263,10 @@ "performance.forge.FMLControlledNamespacedRegistryMixin_TrimAvailabilityMap", "performance.forge.ItemLayerModelMixin_ReduceQuadCount", "performance.forge.JarDiscovererMixin_ReplaceRegex", + "performance.forge.LightUtilMixin_OptimizeNormals", "performance.forge.ModDiscovererMixin_Logging", "performance.forge.ModDiscovererMixin_ReplaceRegex", + "performance.forge.VertexLighterFlatMixin_OptimizeNormals", "performance.hudcaching.EntityRendererMixin_HUDCaching", "performance.hudcaching.FramebufferMixin_HUDCaching", "performance.hudcaching.GlStateManagerMixin_HUDCaching",