Port biome palette and chunk section optimizations from Hydrogen

This commit is contained in:
embeddedt 2023-01-22 20:11:03 -05:00
parent ad5fcf44e5
commit 6b28cb5ebc
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
4 changed files with 191 additions and 1 deletions

View File

@ -33,6 +33,8 @@ public class ModernFixEarlyConfig {
this.addMixinRule("perf.sync_executor_sleep", true);
this.addMixinRule("perf.scan_cache", true);
this.addMixinRule("perf.parallel_blockstate_cache_rebuild", true);
this.addMixinRule("perf.compress_biome_container", true);
this.addMixinRule("perf.nuke_empty_chunk_sections", true);
this.addMixinRule("perf.deduplicate_location", true);
this.addMixinRule("safety", true);
this.addMixinRule("launch.transformer_cache", false);

View File

@ -0,0 +1,148 @@
package org.embeddedt.modernfix.mixin.perf.compress_biome_container;
import it.unimi.dsi.fastutil.objects.Reference2ShortMap;
import it.unimi.dsi.fastutil.objects.Reference2ShortOpenHashMap;
import net.minecraft.util.BitArray;
import net.minecraft.util.IObjectIntIterable;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeContainer;
import net.minecraft.world.biome.provider.BiomeProvider;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(BiomeContainer.class)
public class MixinBiomeContainer {
@Mutable
@Shadow
@Final
private Biome[] biomes;
@Shadow
@Final
private IObjectIntIterable<Biome> biomeRegistry;
@Shadow
@Final
private static int WIDTH_BITS;
private Biome[] palette;
private BitArray intArray;
@Inject(method = "<init>(Lnet/minecraft/util/IObjectIntIterable;[I)V", at = @At("RETURN"))
private void reinit1(IObjectIntIterable p_i241970_1_, int[] p_i241970_2_, CallbackInfo ci) {
this.createCompact();
}
@Inject(method = "<init>(Lnet/minecraft/util/IObjectIntIterable;[Lnet/minecraft/world/biome/Biome;)V", at = @At("RETURN"))
private void reinit2(IObjectIntIterable p_i241971_1_, Biome[] p_i241971_2_, CallbackInfo ci) {
this.createCompact();
}
@Inject(method = "<init>(Lnet/minecraft/util/IObjectIntIterable;Lnet/minecraft/util/math/ChunkPos;Lnet/minecraft/world/biome/provider/BiomeProvider;)V", at = @At("RETURN"))
private void reinit3(IObjectIntIterable p_i241968_1_, ChunkPos p_i241968_2_, BiomeProvider p_i241968_3_, CallbackInfo ci) {
this.createCompact();
}
@Inject(method = "<init>(Lnet/minecraft/util/IObjectIntIterable;Lnet/minecraft/util/math/ChunkPos;Lnet/minecraft/world/biome/provider/BiomeProvider;[I)V", at = @At("RETURN"))
private void reinit4(IObjectIntIterable p_i241969_1_, ChunkPos p_i241969_2_, BiomeProvider p_i241969_3_, int[] p_i241969_4_, CallbackInfo ci) {
this.createCompact();
}
private void createCompact() {
if (this.intArray != null || this.biomes[0] == null) {
return;
}
Reference2ShortOpenHashMap<Biome> paletteTable = this.createPalette();
Biome[] paletteIndexed = new Biome[paletteTable.size()];
for (Reference2ShortMap.Entry<Biome> entry : paletteTable.reference2ShortEntrySet()) {
paletteIndexed[entry.getShortValue()] = entry.getKey();
}
int packedIntSize = Math.max(2, MathHelper.ceillog2(paletteTable.size()));
BitArray integerArray = new BitArray(packedIntSize, BiomeContainer.BIOMES_SIZE);
Biome prevBiome = null;
short prevId = -1;
for (int i = 0; i < this.biomes.length; i++) {
Biome biome = this.biomes[i];
short id;
if (prevBiome == biome) {
id = prevId;
} else {
id = paletteTable.getShort(biome);
if (id < 0) {
throw new IllegalStateException("Palette is missing entry: " + biome);
}
prevId = id;
prevBiome = biome;
}
integerArray.set(i, id);
}
this.palette = paletteIndexed;
this.intArray = integerArray;
this.biomes = null;
}
private Reference2ShortOpenHashMap<Biome> createPalette() {
Reference2ShortOpenHashMap<Biome> map = new Reference2ShortOpenHashMap<>();
map.defaultReturnValue(Short.MIN_VALUE);
Biome prevObj = null;
short id = 0;
for (Biome obj : this.biomes) {
if (obj == prevObj) {
continue;
}
if (map.getShort(obj) < 0) {
map.put(obj, id++);
}
prevObj = obj;
}
return map;
}
/**
* @author JellySquid
* @reason Use paletted lookup
*/
@Overwrite
public int[] writeBiomes() {
int size = this.intArray.getSize();
int[] array = new int[size];
for(int i = 0; i < size; ++i) {
array[i] = this.biomeRegistry.getId(this.palette[this.intArray.get(i)]);
}
return array;
}
/**
* @author JellySquid
* @reason Use paletted lookup
*/
@Overwrite
public Biome getNoiseBiome(int biomeX, int biomeY, int biomeZ) {
int x = biomeX & BiomeContainer.HORIZONTAL_MASK;
int y = MathHelper.clamp(biomeY, 0, BiomeContainer.VERTICAL_MASK);
int z = biomeZ & BiomeContainer.HORIZONTAL_MASK;
return this.palette[this.intArray.get(y << WIDTH_BITS + WIDTH_BITS | z << WIDTH_BITS | x)];
}
}

View File

@ -0,0 +1,38 @@
package org.embeddedt.modernfix.mixin.perf.nuke_empty_chunk_sections;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.palette.UpgradeData;
import net.minecraft.world.ITickList;
import net.minecraft.world.World;
import net.minecraft.world.biome.BiomeContainer;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkSection;
import org.spongepowered.asm.mixin.Final;
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.callback.CallbackInfo;
import java.util.function.Consumer;
@Mixin(Chunk.class)
public class MixinChunk {
@Shadow @Final private ChunkSection[] sections;
@Inject(method = "<init>(Lnet/minecraft/world/World;" +
"Lnet/minecraft/util/math/ChunkPos;Lnet/minecraft/world/biome/BiomeContainer;" +
"Lnet/minecraft/util/palette/UpgradeData;Lnet/minecraft/world/ITickList;" +
"Lnet/minecraft/world/ITickList;J[Lnet/minecraft/world/chunk/ChunkSection;Ljava/util/function/Consumer;)V",
at = @At("RETURN"))
private void reinit(World world, ChunkPos pos, BiomeContainer container, UpgradeData data,
ITickList list1, ITickList list2, long inhabited,
ChunkSection[] oldSections, Consumer consumer, CallbackInfo ci) {
/* taken from Hydrogen */
for(int i = 0; i < this.sections.length; i++) {
if(ChunkSection.isEmpty(this.sections[i])) {
this.sections[i] = null;
}
}
}
}

View File

@ -23,7 +23,9 @@
"perf.parallel_blockstate_cache_rebuild.BlockCallbacksMixin",
"perf.parallel_blockstate_cache_rebuild.ShapeCacheMixin",
"perf.deduplicate_location.MixinResourceLocation",
"perf.sync_executor_sleep.SyncExecutorMixin"
"perf.sync_executor_sleep.SyncExecutorMixin",
"perf.compress_biome_container.MixinBiomeContainer",
"perf.nuke_empty_chunk_sections.MixinChunk"
],
"client": [
"perf.skip_first_datapack_reload.MinecraftMixin",