Tweak model loading

This commit is contained in:
embeddedt 2023-02-11 09:31:28 -05:00
parent 80a4585efd
commit 928d2e3f02
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
5 changed files with 111 additions and 3 deletions

View File

@ -134,13 +134,13 @@ dependencies {
runtimeOnly fg.deobf("curse.maven:lazydfu-460819:${lazydfu_version}")
compileOnly fg.deobf("mezz.jei:jei-${minecraft_version}:${jei_version}")
compileOnly fg.deobf("curse.maven:ferritecore-429235:4074330")
if(include_optimization_mods.toBoolean()) {
runtimeOnly fg.deobf("curse.maven:roadrunner-529754:3683120")
runtimeOnly fg.deobf("curse.maven:rubidium-574856:3949659")
runtimeOnly fg.deobf("curse.maven:noexperimental-407174:3188120")
runtimeOnly fg.deobf("curse.maven:spark-361579:3767277")
runtimeOnly fg.deobf("curse.maven:ferritecore-429235:4074330")
runtimeOnly fg.deobf("mezz.jei:jei-${minecraft_version}:${jei_version}")
}

View File

@ -0,0 +1,47 @@
package org.embeddedt.modernfix.mixin.perf.faster_baking;
import com.mojang.datafixers.util.Pair;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.BlockModelShapes;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ModelManager;
import net.minecraft.client.renderer.model.ModelResourceLocation;
import net.minecraft.util.Util;
import net.minecraft.util.registry.Registry;
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.ArrayList;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
@Mixin(BlockModelShapes.class)
public abstract class BlockModelShapesMixin {
@Shadow @Final private ModelManager modelManager;
@Shadow @Final private Map<BlockState, IBakedModel> modelByStateCache;
/**
* @author embeddedt
* @reason parallelize cache rebuild
*/
@Overwrite
public void rebuildCache() {
this.modelByStateCache.clear();
ArrayList<CompletableFuture<Pair<BlockState, IBakedModel>>> futures = new ArrayList<>();
for(Block block : Registry.BLOCK) {
block.getStateDefinition().getPossibleStates().forEach((state) -> {
futures.add(CompletableFuture.supplyAsync(() -> {
return Pair.of(state, this.modelManager.getModel(BlockModelShapes.stateToModelLocation(state)));
}, Util.backgroundExecutor()));
});
}
for(CompletableFuture<Pair<BlockState, IBakedModel>> future : futures) {
Pair<BlockState, IBakedModel> pair = future.join();
this.modelByStateCache.put(pair.getFirst(), pair.getSecond());
}
}
}

View File

@ -16,6 +16,7 @@ import net.minecraftforge.fml.loading.progress.StartupMessageManager;
import org.apache.commons.lang3.tuple.Triple;
import org.apache.logging.log4j.Logger;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.ModernFixClient;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@ -44,16 +45,72 @@ public abstract class ModelBakeryMixin {
@Shadow @Final private Map<ResourceLocation, IUnbakedModel> unbakedCache;
@Shadow @Mutable
@Final private Map<Triple<ResourceLocation, TransformationMatrix, Boolean>, IBakedModel> bakedCache;
@Shadow @Final private static ItemModelGenerator ITEM_MODEL_GENERATOR;
@Shadow @Final public static BlockModel GENERATION_MARKER;
@Shadow public abstract IUnbakedModel getModel(ResourceLocation p_209597_1_);
private ConcurrentHashMap<ResourceLocation, IdentityHashMap<IModelTransform, IBakedModel>> fasterBakedCache;
private Map<Boolean, List<Map.Entry<ResourceLocation, IUnbakedModel>>> modelsToBakeParallel;
private boolean canBakeParallel(IUnbakedModel unbakedModel) {
if(unbakedModel instanceof BlockModel) {
BlockModel model = (BlockModel)unbakedModel;
return !model.customData.hasCustomGeometry();
} else
} else if((unbakedModel instanceof Multipart) || (unbakedModel instanceof VariantList))
return true;
else
return false;
}
private IBakedModel bakeModel(ResourceLocation pLocation, IModelTransform pTransform, java.util.function.Function<RenderMaterial, net.minecraft.client.renderer.texture.TextureAtlasSprite> textureGetter) {
IUnbakedModel iunbakedmodel = this.unbakedCache.get(pLocation);
if(iunbakedmodel == null)
throw new IllegalStateException("we should not be baking unloaded models");
if (iunbakedmodel instanceof BlockModel) {
BlockModel blockmodel = (BlockModel)iunbakedmodel;
if (blockmodel.getRootModel() == GENERATION_MARKER) {
return ITEM_MODEL_GENERATOR.generateBlockModel(textureGetter, blockmodel).bake((ModelBakery)(Object)this, blockmodel, this.atlasSet::getSprite, pTransform, pLocation, false);
}
}
/* Ensure only one thread builds at a time if needed */
if(canBakeParallel(iunbakedmodel)) {
return iunbakedmodel.bake((ModelBakery)(Object)this, textureGetter, pTransform, pLocation);
} else {
synchronized(this.bakedCache) {
return iunbakedmodel.bake((ModelBakery)(Object)this, textureGetter, pTransform, pLocation);
}
}
}
/**
* @author embeddedt
* @reason avoid rehashing model data when unneeded
*/
@Overwrite(remap = false)
public IBakedModel getBakedModel(ResourceLocation pLocation, IModelTransform pTransform, java.util.function.Function<RenderMaterial, net.minecraft.client.renderer.texture.TextureAtlasSprite> textureGetter) {
/* Try to retrieve the model */
IdentityHashMap<IModelTransform, IBakedModel> modelsForLocation = this.fasterBakedCache.computeIfAbsent(pLocation, loc -> new IdentityHashMap<>());
synchronized (modelsForLocation) {
IBakedModel result = modelsForLocation.get(pTransform);
if(result != null)
return result;
}
/* Otherwise, bake the model and then store it */
synchronized(this.unbakedCache) {
this.getModel(pLocation);
}
IBakedModel result = bakeModel(pLocation, pTransform, textureGetter);
synchronized (modelsForLocation) {
modelsForLocation.put(pTransform, result);
}
return result;
}
@Inject(method = "processLoading", at = @At(value = "INVOKE", target = "Lnet/minecraft/profiler/IProfiler;pop()V"))
private void bakeModels(IProfiler pProfiler, int p_i226056_4_, CallbackInfo ci) {
pProfiler.popPush("atlas");
@ -67,7 +124,8 @@ public abstract class ModelBakeryMixin {
pProfiler.popPush("baking");
StartupMessageManager.mcLoaderConsumer().ifPresent(c -> c.accept("Baking models"));
this.atlasSet = new SpriteMap(this.atlasPreparations.values().stream().map(Pair::getFirst).collect(Collectors.toList()));
this.bakedCache = new ConcurrentHashMap<>();
this.bakedCache = Collections.emptyMap();
this.fasterBakedCache = new ConcurrentHashMap<>();
this.modelsToBakeParallel = this.unbakedCache.entrySet().stream()
.collect(Collectors.partitioningBy(entry -> {
IUnbakedModel unbakedModel = entry.getValue();

View File

@ -18,6 +18,7 @@ import net.minecraft.util.ResourceLocation;
import net.minecraft.util.Util;
import net.minecraft.util.math.vector.TransformationMatrix;
import net.minecraft.util.registry.Registry;
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.util.AsyncStopwatch;
import org.spongepowered.asm.mixin.Final;
@ -64,6 +65,7 @@ public abstract class ModelBakeryMixin {
@Inject(method = "processLoading", at = @At(value = "INVOKE", target = "Lnet/minecraft/profiler/IProfiler;popPush(Ljava/lang/String;)V", ordinal = 0))
private void preloadJsonModels(IProfiler profilerIn, int maxMipmapLevel, CallbackInfo ci) {
StartupMessageManager.mcLoaderConsumer().ifPresent(c -> c.accept("Loading models"));
profilerIn.popPush("loadblockstates");
AsyncStopwatch.measureAndLogSerialRunningTime("Parallel blockstate loading", () -> {
ThreadLocal<BlockModelDefinition.ContainerHolder> containerHolder = ThreadLocal.withInitial(BlockModelDefinition.ContainerHolder::new);

View File

@ -54,6 +54,7 @@
"perf.blast_search_trees.MinecraftMixin",
"perf.blast_search_trees.IngredientFilterInvoker",
"perf.faster_baking.ModelBakeryMixin",
"perf.faster_baking.BlockModelShapesMixin",
"perf.cache_model_materials.VanillaModelMixin",
"perf.cache_model_materials.MultipartMixin",
"bugfix.packet_leak.ClientPlayNetHandlerMixin",