Skip to content

Commit

Permalink
perf: make HotSpot C2 happier in AquiferSampler$Impl
Browse files Browse the repository at this point in the history
  • Loading branch information
ishland committed Mar 31, 2024
1 parent 728819e commit 368487c
Showing 1 changed file with 129 additions and 217 deletions.
Expand Up @@ -11,7 +11,8 @@
import net.minecraft.world.gen.chunk.AquiferSampler;
import net.minecraft.world.gen.chunk.ChunkNoiseSampler;
import net.minecraft.world.gen.densityfunction.DensityFunction;
import org.jetbrains.annotations.Nullable;
import org.apache.commons.lang3.mutable.MutableDouble;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
Expand All @@ -24,7 +25,7 @@
import static net.minecraft.util.math.BlockPos.SIZE_BITS_X;

@Mixin(AquiferSampler.Impl.class)
public class MixinAquiferSamplerImpl {
public abstract class MixinAquiferSamplerImpl {

@Unique
private static final int WATER_LEVEL_MAGIC_1 = 64 - BlockPos.BIT_SHIFT_X - SIZE_BITS_X;
Expand Down Expand Up @@ -101,249 +102,160 @@ public class MixinAquiferSamplerImpl {
@Final
private AquiferSampler.FluidLevelSampler fluidLevelSampler;

@Unique
private Random randomInstance;
@Shadow protected abstract int index(int x, int y, int z);

@Shadow
protected static double maxDistance(int i, int a) {
throw new AbstractMethodError();
}

@Shadow protected abstract double calculateDensity(DensityFunction.NoisePos pos, MutableDouble mutableDouble, AquiferSampler.FluidLevel fluidLevel, AquiferSampler.FluidLevel fluidLevel2);

@Inject(method = "<init>", at = @At("RETURN"))
private void onInit(CallbackInfo info) {
this.randomInstance = RandomUtils.getRandom(this.randomDeriver);
// preload position cache
if (this.blockPositions.length % (this.sizeX * this.sizeZ) != 0) {
throw new AssertionError("Array length");
}
int sizeY = this.blockPositions.length / (this.sizeX * this.sizeZ);
final Random random = RandomUtils.getRandom(this.randomDeriver);
// index: z, x, y
for (int z = 0; z < this.sizeZ; z++) {
for (int x = 0; x < this.sizeX; x++) {
for (int y = 0; y < sizeY; y++) {
final int x1 = x + this.startX;
final int y1 = y + this.startY;
final int z1 = z + this.startZ;
RandomUtils.derive(this.randomDeriver, random, x1, y1, z1);
this.blockPositions[this.index(x1, y1, z1)] = BlockPos.asLong(x1 * 16 + random.nextInt(10), y1 * 12 + random.nextInt(9), z1 * 16 + random.nextInt(10));
}
}
}
for (long blockPosition : this.blockPositions) {
if (blockPosition == Long.MAX_VALUE) {
throw new AssertionError("Array initialization");
}
}
}

/**
* @author ishland
* @reason optimize
* @reason make C2 happier by splitting method into two
*/
@Overwrite
@Nullable
public BlockState apply(DensityFunction.NoisePos arg, double d) {
final int blockX = arg.blockX();
final int blockY = arg.blockY();
final int blockZ = arg.blockZ();
if (d > 0.0) {
public BlockState apply(DensityFunction.NoisePos pos, double density) {
int i = pos.blockX();
int j = pos.blockY();
int k = pos.blockZ();
if (density > 0.0) {
this.needsFluidTick = false;
return null;
} else {
AquiferSampler.FluidLevel fluidLevel = this.fluidLevelSampler.getFluidLevel(blockX, blockY, blockZ);
if (fluidLevel.getBlockState(blockY).isOf(Blocks.LAVA)) {
AquiferSampler.FluidLevel fluidLevel = this.fluidLevelSampler.getFluidLevel(i, j, k);
if (fluidLevel.getBlockState(j).isOf(Blocks.LAVA)) {
this.needsFluidTick = false;
return Blocks.LAVA.getDefaultState();
} else {
int l = Math.floorDiv(blockX - 5, 16);
int m = Math.floorDiv(blockY + 1, 12);
int n = Math.floorDiv(blockZ - 5, 16);
int o = Integer.MAX_VALUE;
int p = Integer.MAX_VALUE;
int q = Integer.MAX_VALUE;
long r = 0L;
long s = 0L;
long t = 0L;

for (int u = 0; u <= 1; ++u) {
for (int v = -1; v <= 1; ++v) {
for (int w = 0; w <= 1; ++w) {
int x = l + u;
int y = m + v;
int z = n + w;
int aa = ((y - this.startY) * this.sizeZ + z - this.startZ) * this.sizeX + x - this.startX;
long ab = this.blockPositions[aa];
long ac;
if (ab != Long.MAX_VALUE) {
ac = ab;
} else {
// C2ME - reuse random instance
RandomUtils.derive(this.randomDeriver, this.randomInstance, x, y, z);
final int i1 = randomInstance.nextInt(10);
final int i2 = randomInstance.nextInt(9);
final int i3 = randomInstance.nextInt(10);
ac = BlockPos.asLong(x * 16 + i1, y * 12 + i2, z * 16 + i3);
this.blockPositions[aa] = ac;
}

int ad = (int) ((ac << WATER_LEVEL_MAGIC_1) >> WATER_LEVEL_MAGIC_2) - blockX; // C2ME - inline
int ae = (int) ((ac << WATER_LEVEL_MAGIC_3) >> WATER_LEVEL_MAGIC_4) - blockY; // C2ME - inline
int af = (int) ((ac << WATER_LEVEL_MAGIC_5) >> WATER_LEVEL_MAGIC_6) - blockZ; // C2ME - inline
int ag = ad * ad + ae * ae + af * af;
if (o >= ag) {
t = s;
s = r;
r = ac;
q = p;
p = o;
o = ag;
} else if (p >= ag) {
t = s;
s = ac;
q = p;
p = ag;
} else if (q >= ag) {
t = ac;
q = ag;
}
}
}
}

AquiferSampler.FluidLevel fluidLevel2 = this.getWaterLevel(r);
double e = 1.0 - Math.abs(p - o) / 25.0; // C2ME - inline
final BlockState fluidLevel2BlockState = fluidLevel2.getBlockState(blockY);
if (e <= 0.0) {
this.needsFluidTick = e >= NEEDS_FLUID_TICK_DISTANCE_THRESHOLD;
return fluidLevel2BlockState;
final Result1 result = getResult1(i, j, k);

AquiferSampler.FluidLevel fluidLevel2 = this.getWaterLevel(result.r());
double d = maxDistance(result.o(), result.p());
BlockState blockState = fluidLevel2.getBlockState(j);
if (d <= 0.0) {
this.needsFluidTick = d >= NEEDS_FLUID_TICK_DISTANCE_THRESHOLD;
return blockState;
} else if (blockState.isOf(Blocks.WATER) && this.fluidLevelSampler.getFluidLevel(i, j - 1, k).getBlockState(j - 1).isOf(Blocks.LAVA)) {
this.needsFluidTick = true;
return blockState;
} else {
final boolean fluidLevel2BlockStateOfWater = fluidLevel2BlockState.isOf(Blocks.WATER);
if (fluidLevel2BlockStateOfWater && this.fluidLevelSampler.getFluidLevel(blockX, blockY - 1, blockZ).getBlockState(blockY - 1).isOf(Blocks.LAVA)) {
this.needsFluidTick = true;
return fluidLevel2BlockState;
MutableDouble mutableDouble = new MutableDouble(Double.NaN);
AquiferSampler.FluidLevel fluidLevel3 = this.getWaterLevel(result.s());
double e = d * this.calculateDensity(pos, mutableDouble, fluidLevel2, fluidLevel3);
if (density + e > 0.0) {
this.needsFluidTick = false;
return null;
} else {
double mutableDouble = Double.NaN;
AquiferSampler.FluidLevel fluidLevel3 = this.getWaterLevel(s);
double result1;
final BlockState fluidLevel3BlockState = fluidLevel3.getBlockState(blockY);
final boolean fluidLevel2BlockStateOfLava = fluidLevel2BlockState.isOf(Blocks.LAVA);
final boolean fluidLevel3BlockStateOfLava = fluidLevel3BlockState.isOf(Blocks.LAVA);
final boolean fluidLevel3BlockStateOfWater = fluidLevel3BlockState.isOf(Blocks.WATER);
if ((!fluidLevel2BlockStateOfLava || !fluidLevel3BlockStateOfWater) && (!fluidLevel2BlockStateOfWater || !fluidLevel3BlockStateOfLava)) {
int j2 = Math.abs(fluidLevel2.y - fluidLevel3.y);
if (j2 == 0) {
result1 = 0.0;
} else {
double d2 = 0.5 * (fluidLevel2.y + fluidLevel3.y);
double e2 = blockY + 0.5 - d2;
double f2 = j2 / 2.0;
double o2 = f2 - Math.abs(e2);
double q2;
if (e2 > 0.0) {
double p2 = 0.0 + o2;
q2 = p2 > 0.0 ? p2 / 1.5 : p2 / 2.5;
} else {
double p2 = 3.0 + o2;
q2 = p2 > 0.0 ? p2 / 3.0 : p2 / 10.0;
}

double r2;
if (!(q2 < -2.0) && !(q2 > 2.0)) {
double t2 = this.barrierNoise.sample(arg);
mutableDouble = t2;
r2 = t2;
} else {
r2 = 0.0;
}

result1 = 2.0 * (r2 + q2);
AquiferSampler.FluidLevel fluidLevel4 = this.getWaterLevel(result.t());
double f = maxDistance(result.o(), result.q());
if (f > 0.0) {
double g = d * f * this.calculateDensity(pos, mutableDouble, fluidLevel2, fluidLevel4);
if (density + g > 0.0) {
this.needsFluidTick = false;
return null;
}
} else {
result1 = 2.0;
}
double f = e * result1;
if (d + f > 0.0) {
this.needsFluidTick = false;
return null;
} else {
AquiferSampler.FluidLevel fluidLevel4 = this.getWaterLevel(t);
double g = 1.0 - (double) Math.abs(q - o) / 25.0;
final BlockState fluidLevel4BlockState = fluidLevel4.getBlockState(blockY);
final boolean fluidLevel4BlockStateOfWater = fluidLevel4BlockState.isOf(Blocks.WATER);
final boolean fluidLevel4BlockStateOfLava = fluidLevel4BlockState.isOf(Blocks.LAVA);
if (g > 0.0) {
double result;
if ((!fluidLevel2BlockStateOfLava || !fluidLevel4BlockStateOfWater) && (!fluidLevel2BlockStateOfWater || !fluidLevel4BlockStateOfLava)) {
int j1 = Math.abs(fluidLevel2.y - fluidLevel4.y);
if (j1 == 0) {
result = 0.0;
} else {
double d1 = 0.5 * (fluidLevel2.y + fluidLevel4.y);
double e1 = blockY + 0.5 - d1;
double f1 = j1 / 2.0;
double o1 = f1 - Math.abs(e1);
double q1;
if (e1 > 0.0) {
double p1 = 0.0 + o1;
q1 = p1 > 0.0 ? p1 / 1.5 : p1 / 2.5;
} else {
double p1 = 3.0 + o1;
q1 = p1 > 0.0 ? p1 / 3.0 : p1 / 10.0;
}

double r1;
if (!(q1 < -2.0) && !(q1 > 2.0)) {
if (Double.isNaN(mutableDouble)) {
double t1 = this.barrierNoise.sample(arg);
mutableDouble = t1;
r1 = t1;
} else {
r1 = mutableDouble;
}
} else {
r1 = 0.0;
}

result = 2.0 * (r1 + q1);
}
} else {
result = 2.0;
}
double h = e * g * result;
if (d + h > 0.0) {
this.needsFluidTick = false;
return null;
}
}

double h = 1.0 - (double) Math.abs(q - p) / 25.0;
if (h > 0.0) {
double result;
if ((!fluidLevel3BlockStateOfLava || !fluidLevel4BlockStateOfWater) && (!fluidLevel3BlockStateOfWater || !fluidLevel4BlockStateOfLava)) {
int j1 = Math.abs(fluidLevel3.y - fluidLevel4.y);
if (j1 == 0) {
result = 0.0;
} else {
double d1 = 0.5 * (fluidLevel3.y + fluidLevel4.y);
double e1 = blockY + 0.5 - d1;
double f1 = j1 / 2.0;
double o1 = f1 - Math.abs(e1);
double q1;
if (e1 > 0.0) {
double p1 = 0.0 + o1;
q1 = p1 > 0.0 ? p1 / 1.5 : p1 / 2.5;
} else {
double p1 = 3.0 + o1;
q1 = p1 > 0.0 ? p1 / 3.0 : p1 / 10.0;
}

double r1;
if (!(q1 < -2.0) && !(q1 > 2.0)) {
if (Double.isNaN(mutableDouble)) {
double t1 = this.barrierNoise.sample(arg);
mutableDouble = t1;
r1 = t1;
} else {
r1 = mutableDouble;
}
} else {
r1 = 0.0;
}

result = 2.0 * (r1 + q1);
}
} else {
result = 2.0;
}
double ah = e * h * result;
if (d + ah > 0.0) {
this.needsFluidTick = false;
return null;
}
double g = maxDistance(result.p(), result.q());
if (g > 0.0) {
double h = d * g * this.calculateDensity(pos, mutableDouble, fluidLevel3, fluidLevel4);
if (density + h > 0.0) {
this.needsFluidTick = false;
return null;
}

this.needsFluidTick = true;
return fluidLevel2BlockState;
}

this.needsFluidTick = true;
return blockState;
}
}
}
}
}

@NotNull
private Result1 getResult1(int i, int j, int k) {
int l = Math.floorDiv(i - 5, 16);
int m = Math.floorDiv(j + 1, 12);
int n = Math.floorDiv(k - 5, 16);
int o = Integer.MAX_VALUE;
int p = Integer.MAX_VALUE;
int q = Integer.MAX_VALUE;
long r = 0L;
long s = 0L;
long t = 0L;

for(int u = 0; u <= 1; ++u) {
for(int v = -1; v <= 1; ++v) {
for(int w = 0; w <= 1; ++w) {
int x = l + u;
int y = m + v;
int z = n + w;
int aa = this.index(x, y, z);
long ab = this.blockPositions[aa];
long ac = ab; // cache preloaded

int ad = BlockPos.unpackLongX(ac) - i;
int ae = BlockPos.unpackLongY(ac) - j;
int af = BlockPos.unpackLongZ(ac) - k;
int ag = ad * ad + ae * ae + af * af;
if (o >= ag) {
t = s;
s = r;
r = ac;
q = p;
p = o;
o = ag;
} else if (p >= ag) {
t = s;
s = ac;
q = p;
p = ag;
} else if (q >= ag) {
t = ac;
q = ag;
}
}
}
}
Result1 result = new Result1(o, p, q, r, s, t);
return result;
}

@SuppressWarnings("MixinInnerClass")
private record Result1(int o, int p, int q, long r, long s, long t) {
}


/**
* @author ishland
* @reason optimize
Expand Down

0 comments on commit 368487c

Please sign in to comment.