From 1fc1e132cbee52c0560b5470a32522d8bde46947 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:22:06 -0400 Subject: [PATCH 1/4] Fix injector target --- .../modernfix/mixin/perf/nbt_memory_usage/CompoundTagMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/nbt_memory_usage/CompoundTagMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/nbt_memory_usage/CompoundTagMixin.java index 51072a68..348a8f4b 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/nbt_memory_usage/CompoundTagMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/nbt_memory_usage/CompoundTagMixin.java @@ -36,7 +36,7 @@ public class CompoundTagMixin { * @author embeddedt * @reason use more efficient method when copying canonizing string map */ - @Inject(method = "copy()Lnet/minecraft/nbt/Tag;", at = @At("HEAD"), cancellable = true) + @Inject(method = "copy()Lnet/minecraft/nbt/CompoundTag;", at = @At("HEAD"), cancellable = true) public void copyEfficient(CallbackInfoReturnable cir) { if(this.tags instanceof CanonizingStringMap) { cir.setReturnValue(new CompoundTag(CanonizingStringMap.deepCopy((CanonizingStringMap)this.tags, Tag::copy))); From 91d1cb3962f260cff8afbb68dc0b20555695b444 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 26 Apr 2023 19:11:39 -0400 Subject: [PATCH 2/4] Bypass slow PngInfo class during texture loading Thanks to @Asek3 for pointing out this bottleneck --- .../core/config/ModernFixEarlyConfig.java | 1 + .../TextureAtlasMixin.java | 110 ++++++++++++++++++ .../resources/META-INF/accesstransformer.cfg | 3 +- src/main/resources/modernfix.mixins.json | 2 + 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/faster_texture_loading/TextureAtlasMixin.java 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 647aaed0..0f859f12 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -88,6 +88,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.datapack_reload_exceptions", true); this.addMixinRule("perf.async_locator", true); this.addMixinRule("perf.faster_texture_stitching", true); + this.addMixinRule("perf.faster_texture_loading", true); this.addMixinRule("perf.kubejs", modPresent("kubejs")); 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/mixin/perf/faster_texture_loading/TextureAtlasMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_texture_loading/TextureAtlasMixin.java new file mode 100644 index 00000000..1e326451 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_texture_loading/TextureAtlasMixin.java @@ -0,0 +1,110 @@ +package org.embeddedt.modernfix.mixin.perf.faster_texture_loading; + +import com.mojang.blaze3d.platform.NativeImage; +import com.mojang.datafixers.util.Pair; +import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.metadata.animation.AnimationMetadataSection; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.Resource; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.fml.ModLoader; +import org.apache.commons.lang3.tuple.Triple; +import org.embeddedt.modernfix.ModernFix; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.io.IOException; +import java.io.InputStream; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; + +@Mixin(TextureAtlas.class) +public abstract class TextureAtlasMixin { + @Shadow protected abstract ResourceLocation getResourceLocation(ResourceLocation location); + + @Shadow protected abstract Collection getBasicSpriteInfos(ResourceManager resourceManager, Set spriteLocations); + + private Map> loadedImages; + private boolean usingFasterLoad; + /** + * @author embeddedt + * @reason simplify texture loading by loading whole image once, avoid slow PngInfo code + */ + @Redirect(method = "prepareToStitch", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/texture/TextureAtlas;getBasicSpriteInfos(Lnet/minecraft/server/packs/resources/ResourceManager;Ljava/util/Set;)Ljava/util/Collection;")) + private Collection loadImages(TextureAtlas atlas, ResourceManager manager, Set imageLocations) { + usingFasterLoad = ModLoader.isLoadingStateValid(); + // bail if Forge is erroring to avoid AT crashes + if(!usingFasterLoad) { + return getBasicSpriteInfos(manager, imageLocations); + } + List> futures = new ArrayList<>(); + ConcurrentLinkedQueue results = new ConcurrentLinkedQueue<>(); + loadedImages = new ConcurrentHashMap<>(); + for(ResourceLocation location : imageLocations) { + if(MissingTextureAtlasSprite.getLocation().equals(location)) + continue; + futures.add(CompletableFuture.runAsync(() -> { + try { + ResourceLocation fileLocation = this.getResourceLocation(location); + Resource resource = manager.getResource(fileLocation); + NativeImage image = NativeImage.read(resource.getInputStream()); + AnimationMetadataSection animData = resource.getMetadata(AnimationMetadataSection.SERIALIZER); + if (animData == null) { + animData = AnimationMetadataSection.EMPTY; + } + Pair dimensions = animData.getFrameSize(image.getWidth(), image.getHeight()); + loadedImages.put(location, Pair.of(resource, image)); + results.add(new TextureAtlasSprite.Info(location, dimensions.getFirst(), dimensions.getSecond(), animData)); + } catch(IOException e) { + ModernFix.LOGGER.error("Using missing texture, unable to load {} : {}", location, e); + } catch(RuntimeException e) { + ModernFix.LOGGER.error("Unable to parse metadata from {} : {}", location, e); + } + }, ModernFix.resourceReloadExecutor())); + } + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); + return results; + } + + @Inject(method = "prepareToStitch", at = @At("RETURN")) + private void clearLoadedImages(CallbackInfoReturnable cir) { + loadedImages = Collections.emptyMap(); + } + + @Inject(method = "load(Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite$Info;IIIII)Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;", + at = @At("HEAD"), cancellable = true) + private void loadFromExisting(ResourceManager resourceManager, TextureAtlasSprite.Info spriteInfo, int width, int height, int mipmapLevel, int originX, int originY, CallbackInfoReturnable cir) { + if(!usingFasterLoad) + return; + Pair pair = loadedImages.get(spriteInfo.name()); + if(pair == null) { + ModernFix.LOGGER.error("Texture {} was not loaded in early stage", spriteInfo.name()); + cir.setReturnValue(null); + } else { + TextureAtlasSprite sprite = null; + try { + sprite = ForgeHooksClient.loadTextureAtlasSprite((TextureAtlas)(Object)this, resourceManager, spriteInfo, pair.getFirst(), width, height, originX, originY, mipmapLevel, pair.getSecond()); + if(sprite == null) + sprite = new TextureAtlasSprite((TextureAtlas)(Object)this, spriteInfo, mipmapLevel, width, height, originX, originY, pair.getSecond()); + } catch(RuntimeException e) { + ModernFix.LOGGER.error("Error loading texture {}: {}", spriteInfo.name(), e); + } finally { + try { + pair.getFirst().close(); + } catch(IOException ignored) { + // not much we can do + } + } + cir.setReturnValue(sprite); + } + } +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index ff8cdd75..22dba02c 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -24,4 +24,5 @@ public net.minecraft.block.AbstractBlock$Properties field_235819_u_ # emissiveRe public net.minecraft.block.AbstractBlock$Properties field_235806_h_ # requiresCorrectToolForDrops public net.minecraft.block.AbstractBlock$Properties field_200959_g # destroyTime public net.minecraft.world.server.ServerChunkProvider$ChunkExecutor -public net.minecraft.nbt.CompoundNBT (Ljava/util/Map;)V # \ No newline at end of file +public net.minecraft.nbt.CompoundNBT (Ljava/util/Map;)V # +public net.minecraft.client.renderer.texture.TextureAtlasSprite (Lnet/minecraft/client/renderer/texture/TextureAtlas;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite$Info;IIIIILcom/mojang/blaze3d/platform/NativeImage;)V # \ No newline at end of file diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 80bef802..c96497ec 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -75,6 +75,7 @@ "client": [ "core.MinecraftMixin", "core.SynchedEntityDataMixin", + "core.ModelBakeryMixin", "feature.measure_time.MinecraftMixin", "feature.reduce_loading_screen_freezes.ModelBakeryMixin", "perf.skip_first_datapack_reload.MinecraftMixin", @@ -112,6 +113,7 @@ "perf.cache_model_materials.BlockModelMixin", "perf.cache_model_materials.MultipartMixin", "perf.faster_texture_stitching.StitcherMixin", + "perf.faster_texture_loading.TextureAtlasMixin", "bugfix.packet_leak.ClientPlayNetHandlerMixin", "bugfix.packet_leak.SCustomPayloadPlayPacketMixin", "perf.reuse_datapacks.MinecraftMixin", From 934da3660f0bc0cf9ed131974c398469152864a0 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 26 Apr 2023 19:16:07 -0400 Subject: [PATCH 3/4] Fix debug mixin being checked in --- src/main/resources/modernfix.mixins.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index c96497ec..51765862 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -75,7 +75,6 @@ "client": [ "core.MinecraftMixin", "core.SynchedEntityDataMixin", - "core.ModelBakeryMixin", "feature.measure_time.MinecraftMixin", "feature.reduce_loading_screen_freezes.ModelBakeryMixin", "perf.skip_first_datapack_reload.MinecraftMixin", From 55e7831c57465f552dc04cef8e127546d8f18a44 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Wed, 26 Apr 2023 19:41:05 -0400 Subject: [PATCH 4/4] Mark AE2 and Patchouli as compile only --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index d0825054..63ad555a 100644 --- a/build.gradle +++ b/build.gradle @@ -100,8 +100,8 @@ dependencies { modRuntimeOnly("curse.maven:ferritecore-429235:4074294") modCompileOnly("team.chisel.ctm:CTM:${ctm_version}") modCompileOnly("curse.maven:supermartijncore-454372:4455384") - modImplementation("appeng:appliedenergistics2-forge:11.7.3") - modImplementation("vazkii.patchouli:Patchouli:1.18.2-71.1") + modCompileOnly("appeng:appliedenergistics2-forge:11.7.3") + modCompileOnly("vazkii.patchouli:Patchouli:1.18.2-71.1") } tasks.withType(JavaCompile) {