Skip to content

Commit

Permalink
Fix cache eviction policy in BlockOcclusionCache
Browse files Browse the repository at this point in the history
  • Loading branch information
jellysquid3 committed Jan 27, 2024
1 parent 2bb3023 commit 4bd1002
Showing 1 changed file with 57 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline;

import it.unimi.dsi.fastutil.objects.Object2ByteLinkedOpenHashMap;
import it.unimi.dsi.fastutil.Hash;
import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenCustomHashMap;
import net.minecraft.block.BlockState;
import net.minecraft.block.SideShapeType;
import net.minecraft.util.function.BooleanBiFunction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
Expand All @@ -11,15 +11,20 @@
import net.minecraft.world.BlockView;

public class BlockOcclusionCache {
private static final byte UNCACHED_VALUE = (byte) 127;
private static final int CACHE_SIZE = 512;

private final Object2ByteLinkedOpenHashMap<CachedOcclusionShapeTest> map;
private final CachedOcclusionShapeTest cachedTest = new CachedOcclusionShapeTest();
private final BlockPos.Mutable cpos = new BlockPos.Mutable();
private static final int ENTRY_ABSENT = -1;
private static final int ENTRY_FALSE = 0;
private static final int ENTRY_TRUE = 1;


private final Object2IntLinkedOpenCustomHashMap<ShapeComparison> comparisonLookupTable;
private final ShapeComparison cachedComparisonObject = new ShapeComparison();
private final BlockPos.Mutable cachedPositionObject = new BlockPos.Mutable();

public BlockOcclusionCache() {
this.map = new Object2ByteLinkedOpenHashMap<>(2048, 0.5F);
this.map.defaultReturnValue(UNCACHED_VALUE);
this.comparisonLookupTable = new Object2IntLinkedOpenCustomHashMap<>(CACHE_SIZE, 0.5F, new ShapeComparison.ShapeComparisonStrategy());
this.comparisonLookupTable.defaultReturnValue(ENTRY_ABSENT);
}

/**
Expand All @@ -30,7 +35,7 @@ public BlockOcclusionCache() {
* @return True if the block side facing {@param dir} is not occluded, otherwise false
*/
public boolean shouldDrawSide(BlockState selfState, BlockView view, BlockPos pos, Direction facing) {
BlockPos.Mutable adjPos = this.cpos;
BlockPos.Mutable adjPos = this.cachedPositionObject;
adjPos.set(pos.getX() + facing.getOffsetX(), pos.getY() + facing.getOffsetY(), pos.getZ() + facing.getOffsetZ());

BlockState adjState = view.getBlockState(adjPos);
Expand All @@ -54,73 +59,73 @@ else if (!adjState.isSideSolid(view,pos,facing.getOpposite(), SideShapeType.FULL
}
}

return this.calculate(selfShape, adjShape);
return this.lookup(selfShape, adjShape);
} else {
return true;
}
}

private boolean calculate(VoxelShape selfShape, VoxelShape adjShape) {
CachedOcclusionShapeTest cache = this.cachedTest;
cache.a = selfShape;
cache.b = adjShape;
cache.updateHash();

byte cached = this.map.getByte(cache);

if (cached != UNCACHED_VALUE) {
return cached == 1;
}
private boolean lookup(VoxelShape self, VoxelShape other) {
ShapeComparison comparison = this.cachedComparisonObject;
comparison.self = self;
comparison.other = other;

boolean ret = VoxelShapes.matchesAnywhere(selfShape, adjShape, BooleanBiFunction.ONLY_FIRST);
return switch (this.comparisonLookupTable.getAndMoveToFirst(comparison)) {
case ENTRY_FALSE -> false;
case ENTRY_TRUE -> true;
default -> this.calculate(comparison);
};
}

this.map.put(cache.copy(), (byte) (ret ? 1 : 0));
private boolean calculate(ShapeComparison comparison) {
boolean result = VoxelShapes.matchesAnywhere(comparison.self, comparison.other, BooleanBiFunction.ONLY_FIRST);

if (this.map.size() > 2048) {
this.map.removeLastByte();
while (this.comparisonLookupTable.size() >= CACHE_SIZE) {
this.comparisonLookupTable.removeLastInt();
}

return ret;
this.comparisonLookupTable.putAndMoveToFirst(comparison.copy(), (result ? ENTRY_TRUE : ENTRY_FALSE));

return result;
}

private static final class CachedOcclusionShapeTest {
private VoxelShape a, b;
private int hashCode;
private static final class ShapeComparison {
private VoxelShape self, other;

private CachedOcclusionShapeTest() {
private ShapeComparison() {

}

private CachedOcclusionShapeTest(VoxelShape a, VoxelShape b, int hashCode) {
this.a = a;
this.b = b;
this.hashCode = hashCode;
private ShapeComparison(VoxelShape self, VoxelShape other) {
this.self = self;
this.other = other;
}

public void updateHash() {
int result = System.identityHashCode(this.a);
result = 31 * result + System.identityHashCode(this.b);
public static class ShapeComparisonStrategy implements Hash.Strategy<ShapeComparison> {
@Override
public int hashCode(ShapeComparison value) {
int result = System.identityHashCode(value.self);
result = 31 * result + System.identityHashCode(value.other);

this.hashCode = result;
}
return result;
}

public CachedOcclusionShapeTest copy() {
return new CachedOcclusionShapeTest(this.a, this.b, this.hashCode);
}
@Override
public boolean equals(ShapeComparison a, ShapeComparison b) {
if (a == b) {
return true;
}

@Override
public boolean equals(Object o) {
if (o instanceof CachedOcclusionShapeTest that) {
return this.a == that.a &&
this.b == that.b;
}
if (a == null || b == null) {
return false;
}

return false;
return a.self == b.self && a.other == b.other;
}
}

@Override
public int hashCode() {
return this.hashCode;
public ShapeComparison copy() {
return new ShapeComparison(this.self, this.other);
}
}
}

0 comments on commit 4bd1002

Please sign in to comment.