Port faster texture stitching by SuperCoder79

This commit is contained in:
embeddedt 2023-02-21 11:26:46 -05:00
parent 749c4e1d9d
commit cb6399e820
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
5 changed files with 148 additions and 1 deletions

View File

@ -44,6 +44,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", true);
this.addMixinRule("perf.kubejs", true);
/* Keep this off if JEI isn't installed to prevent breaking vanilla gameplay */
this.addMixinRule("perf.blast_search_trees", FMLLoader.getLoadingModList().getModFileById("jei") != null);

View File

@ -0,0 +1,54 @@
package org.embeddedt.modernfix.mixin.perf.faster_texture_stitching;
import com.mojang.datafixers.util.Pair;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.client.renderer.texture.Stitcher;
import org.embeddedt.modernfix.textures.StbStitcher;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
@Mixin(Stitcher.class)
public class StitcherMixin {
@Shadow @Final private Set<Stitcher.Holder> texturesToBeStitched;
@Shadow private int storageX;
@Shadow private int storageY;
@Shadow @Final private static Comparator<Stitcher.Holder> HOLDER_COMPARATOR;
private List<StbStitcher.LoadableSpriteInfo> loadableSpriteInfos;
/**
* @author embeddedt, SuperCoder79
* @reason Use improved STB stitcher instead of the vanilla implementation, for performance
*/
@Overwrite
public void stitch() {
ObjectArrayList<Stitcher.Holder> holderList = new ObjectArrayList<>(this.texturesToBeStitched);
holderList.sort(HOLDER_COMPARATOR);
Stitcher.Holder[] aholder = holderList.toArray(new Stitcher.Holder[0]);
Pair<Pair<Integer, Integer>, List<StbStitcher.LoadableSpriteInfo>> packingInfo = StbStitcher.packRects(aholder);
this.storageX = packingInfo.getFirst().getFirst();
this.storageY = packingInfo.getFirst().getSecond();
this.loadableSpriteInfos = packingInfo.getSecond();
}
/**
* @author embeddedt, SuperCoder79
* @reason We setup the image ourselves in the StbStitcher, so we just feed this information back into the vanilla code
*/
@Overwrite
public void gatherSprites(Stitcher.SpriteLoader spriteLoader) {
for(StbStitcher.LoadableSpriteInfo info : loadableSpriteInfos) {
spriteLoader.load(info.info, info.width, info.height, info.x, info.y);
}
}
}

View File

@ -0,0 +1,90 @@
package org.embeddedt.modernfix.textures;
import com.google.common.collect.ImmutableList;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.renderer.texture.Stitcher;
import net.minecraft.client.renderer.texture.StitcherException;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.util.Mth;
import org.lwjgl.stb.STBRPContext;
import org.lwjgl.stb.STBRPNode;
import org.lwjgl.stb.STBRPRect;
import org.lwjgl.stb.STBRectPack;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
/* Source: https://github.com/GTNewHorizons/lwjgl3ify/blob/f21364cd3d178aef863458a2faa1f5718a4e350d/src/main/java/me/eigenraven/lwjgl3ify/textures/StbStitcher.java */
public class StbStitcher {
public static Pair<Pair<Integer, Integer>, List<LoadableSpriteInfo>> packRects(Stitcher.Holder[] holders) {
int holderSize = holders.length;
List<LoadableSpriteInfo> infoList = new ArrayList<>();
// Allocate memory for the rectangles and the context
try (STBRPRect.Buffer rectBuf = STBRPRect.malloc(holderSize);
STBRPContext ctx = STBRPContext.malloc(); ) {
// 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;
for (int j = 0; j < holderSize; ++j) {
Stitcher.Holder holder = holders[j];
int width = holder.width;
int height = holder.height;
// The ID here is just the array index, for easy lookup later
rectBuf.get(j).set(j, (short)width, (short)height, (short)0, (short)0, false);
sqSize += (width * height);
}
int size = Mth.smallestEncompassingPowerOfTwo((int) Math.sqrt(sqSize));
int width = size * 2; // needed to fix weirdness in 1.16
int height = size;
// Internal node structure needed for STB
try (STBRPNode.Buffer nodes = STBRPNode.malloc(width + 10)) {
// Initialize the rect packer
STBRectPack.stbrp_init_target(ctx, width, height, nodes);
// Perform rectangle packing
STBRectPack.stbrp_pack_rects(ctx, rectBuf);
for (STBRPRect rect : rectBuf) {
Stitcher.Holder holder = holders[rect.id()];
// Ensure that everything is properly packed!
if (!rect.was_packed()) {
throw new StitcherException(holder.spriteInfo,
Stream.of(holders).map(arg -> arg.spriteInfo).collect(ImmutableList.toImmutableList()));
}
// Initialize the sprite now with the position and size that we've calculated so far
infoList.add(new LoadableSpriteInfo(holder.spriteInfo, width, height, rect.x(), rect.y()));
//holder.spriteInfo.initSprite(size, size, rect.x(), rect.y(), false);
}
return Pair.of(Pair.of(width, height), infoList);
}
}
}
public static class LoadableSpriteInfo {
public final TextureAtlasSprite.Info info;
public final int width;
public final int height;
public final int x;
public final int y;
LoadableSpriteInfo(TextureAtlasSprite.Info info, int width, int height, int x, int y) {
this.info = info;
this.width = width;
this.height = height;
this.x = x;
this.y = y;
}
}
}

View File

@ -4,4 +4,5 @@ public net.minecraft.client.renderer.RenderType$CompositeRenderType <init>(Ljava
public net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase$Cache
public net.minecraft.world.phys.shapes.VoxelShape <init>(Lnet/minecraft/util/math/shapes/VoxelShapePart;)V # <init>
public net.minecraft.client.resources.model.ModelBakery$BlockStateDefinitionException
public net.minecraft.client.renderer.model.ModelBakery field_217849_F # unbakedCache
public net.minecraft.client.renderer.model.ModelBakery field_217849_F # unbakedCache
public net.minecraft.client.renderer.texture.Stitcher$Holder

View File

@ -81,6 +81,7 @@
"perf.faster_baking.ModelManagerMixin",
"perf.cache_model_materials.VanillaModelMixin",
"perf.cache_model_materials.MultipartMixin",
"perf.faster_texture_stitching.StitcherMixin",
"bugfix.packet_leak.ClientPlayNetHandlerMixin",
"bugfix.packet_leak.SCustomPayloadPlayPacketMixin"
],