From 6a7ca1e518ca829ff02efa2fc5585c7f0e92e1c8 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 10 Mar 2023 20:14:11 -0500 Subject: [PATCH 1/4] Remove unnecessary Files.exists call in ModFileResourcePack.getResource() --- .../resourcepacks/ModFileResourcePackMixin.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/resourcepacks/ModFileResourcePackMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/resourcepacks/ModFileResourcePackMixin.java index f4e7d0e9..15d99e15 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/resourcepacks/ModFileResourcePackMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/resourcepacks/ModFileResourcePackMixin.java @@ -3,6 +3,7 @@ package org.embeddedt.modernfix.mixin.perf.resourcepacks; import com.google.common.base.Joiner; import net.minecraft.server.packs.PackType; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.ResourcePackFileNotFoundException; import net.minecraftforge.fml.loading.moddiscovery.ModFile; import net.minecraftforge.fml.packs.ModFileResourcePack; import org.embeddedt.modernfix.util.FileUtil; @@ -14,11 +15,11 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import java.io.IOException; -import java.nio.file.FileSystem; -import java.nio.file.Files; -import java.nio.file.Path; +import java.io.InputStream; +import java.nio.file.*; import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -97,6 +98,15 @@ public abstract class ModFileResourcePackMixin { cir.setReturnValue(this.containedPaths.contains(FileUtil.normalize(path))); } + @Inject(method = "getResource(Ljava/lang/String;)Ljava/io/InputStream;", at = @At(value = "INVOKE", target = "Ljava/nio/file/Files;exists(Ljava/nio/file/Path;[Ljava/nio/file/LinkOption;)Z"), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD) + private void fasterGetResource(String resourcePath, CallbackInfoReturnable cir, Path path) throws IOException { + try { + cir.setReturnValue(Files.newInputStream(path, StandardOpenOption.READ)); + } catch(NoSuchFileException e) { + throw new ResourcePackFileNotFoundException(this.modFile.getFilePath().toFile(), resourcePath); + } + } + /** * @author embeddedt * @reason Use cached listing of mod resources From c481ae0f26037b6abb8a97d5fd6ab556ac493496 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 10 Mar 2023 20:14:29 -0500 Subject: [PATCH 2/4] Make some mods compileOnly --- build.gradle | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index a3395261..079ccc8c 100644 --- a/build.gradle +++ b/build.gradle @@ -86,14 +86,14 @@ dependencies { modRuntimeOnly "curse.maven:lazydfu-460819:${lazydfu_version}" modCompileOnly("mezz.jei:jei-${minecraft_version}:${jei_version}") - modRuntimeOnly("mezz.jei:jei-${minecraft_version}:${jei_version}") + //modRuntimeOnly("mezz.jei:jei-${minecraft_version}:${jei_version}") modCompileOnly("curse.maven:refinedstorage-243076:${refined_storage_version}") - modImplementation("dev.latvian.mods:kubejs-forge:${kubejs_version}") - modImplementation("curse.maven:jeresources-240630:3545538") - modImplementation("curse.maven:jepb-437558:3172880") - modImplementation("curse.maven:babel-436964:3196072") + modCompileOnly("dev.latvian.mods:kubejs-forge:${kubejs_version}") + modCompileOnly("curse.maven:jeresources-240630:3545538") + modCompileOnly("curse.maven:jepb-437558:3172880") + modCompileOnly("curse.maven:babel-436964:3196072") modCompileOnly("curse.maven:twforest-227639:3575220") } From 14e266288a1ff1603c2e44d67f7a381e8c4bbfd3 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 11 Mar 2023 09:38:06 -0500 Subject: [PATCH 3/4] Cache BlockModelShaper.statePropertiesToString --- .../BlockModelShaperMixin.java | 26 +++++++++++++++++++ src/main/resources/modernfix.mixins.json | 1 + 2 files changed, 27 insertions(+) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/BlockModelShaperMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/BlockModelShaperMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/BlockModelShaperMixin.java new file mode 100644 index 00000000..9da0fed8 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/BlockModelShaperMixin.java @@ -0,0 +1,26 @@ +package org.embeddedt.modernfix.mixin.perf.parallelize_model_loading; + +import com.google.common.collect.Interner; +import com.google.common.collect.Interners; +import net.minecraft.client.renderer.block.BlockModelShaper; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Mixin(BlockModelShaper.class) +public class BlockModelShaperMixin { + private static Map stateToPropertiesCache = new ConcurrentHashMap<>(); + + @Redirect(method = "stateToModelLocation(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/world/level/block/state/BlockState;)Lnet/minecraft/client/resources/model/ModelResourceLocation;", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/block/BlockModelShaper;statePropertiesToString(Ljava/util/Map;)Ljava/lang/String;")) + private static String getCachedProperty(Map, Comparable> values, ResourceLocation location, BlockState state) { + /* We intentionally don't use the values parameter inside the lambda to avoid an allocation */ + return stateToPropertiesCache.computeIfAbsent(state, s -> BlockModelShaper.statePropertiesToString(s.getValues())); + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 63666d7b..34c4569b 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -65,6 +65,7 @@ "bugfix.concurrency.RenderTypeMixin", "bugfix.concurrency.MinecraftMixin", "bugfix.concurrency.StaticTagHelperMixin", + "perf.parallelize_model_loading.BlockModelShaperMixin", "perf.parallelize_model_loading.ModelBakeryMixin", "perf.parallelize_model_loading.OBJLoaderMixin", "perf.parallelize_model_loading.multipart.MultipartMixin", From 94bc711008ab64de84f8833a9d7d8bcacf352524 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 11 Mar 2023 09:38:13 -0500 Subject: [PATCH 4/4] Rewrite atlas size calculation logic and re-enable fast texture stitching --- .../core/config/ModernFixEarlyConfig.java | 2 +- .../modernfix/textures/StbStitcher.java | 31 +++++++++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index 97881fa5..760db6ae 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -53,7 +53,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.cache_model_materials", true); this.addMixinRule("perf.datapack_reload_exceptions", true); this.addMixinRule("perf.async_locator", true); - this.addMixinRule("perf.faster_texture_stitching", false); + this.addMixinRule("perf.faster_texture_stitching", true); this.addMixinRule("perf.kubejs", true); this.addMixinRule("perf.faster_singleplayer_load", false); /* Keep this off if JEI isn't installed to prevent breaking vanilla gameplay */ diff --git a/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java b/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java index d2fbb230..7f872371 100644 --- a/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java +++ b/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java @@ -135,7 +135,8 @@ public class StbStitcher { // Initialize the rectangles that we'll be using in the calculation // While that's happening, sum up the area needed to fit all of the images - int sqSize = 0; + int totalArea = 0; + int longestWidth = 0, longestHeight = 0; for (int j = 0; j < holderSize; ++j) { Stitcher.Holder holder = holders[j]; @@ -147,17 +148,29 @@ public class StbStitcher { setWrapper(rect, j, width, height, 0, 0, false); - sqSize += (width * height); + totalArea += (width * height); + longestWidth = Math.max(longestWidth, width); + longestHeight = Math.max(longestHeight, height); } - int size = Mth.smallestEncompassingPowerOfTwo((int) Math.sqrt(sqSize)); - int width = size * 2; // needed to fix weirdness in 1.16 - int height = size; + longestWidth = Mth.smallestEncompassingPowerOfTwo(longestWidth); + longestHeight = Mth.smallestEncompassingPowerOfTwo(longestHeight); + + /* + * The atlas needs to be at least this wide and tall to accomodate oddly shaped sprites. If this is + * not enough, keep doubling the smaller of the two values until its big enough. + */ + while((longestWidth*longestHeight) < totalArea) { + if(longestWidth <= longestHeight) + longestWidth *= 2; + else + longestHeight *= 2; + } // Internal node structure needed for STB - try (STBRPNode.Buffer nodes = STBRPNode.malloc(width + 10)) { + try (STBRPNode.Buffer nodes = STBRPNode.malloc(longestWidth + 10)) { // Initialize the rect packer - STBRectPack.stbrp_init_target(ctx, width, height, nodes); + STBRectPack.stbrp_init_target(ctx, longestWidth, longestHeight, nodes); // Perform rectangle packing STBRectPack.stbrp_pack_rects(ctx, rectBuf); @@ -172,11 +185,11 @@ public class StbStitcher { } // Initialize the sprite now with the position and size that we've calculated so far - infoList.add(new LoadableSpriteInfo(holder.spriteInfo, width, height, getX(rect), getY(rect))); + infoList.add(new LoadableSpriteInfo(holder.spriteInfo, longestWidth, longestHeight, getX(rect), getY(rect))); //holder.spriteInfo.initSprite(size, size, rect.x(), rect.y(), false); } - return Pair.of(Pair.of(width, height), infoList); + return Pair.of(Pair.of(longestWidth, longestHeight), infoList); } } }