diff --git a/core/src/main/java/art/arcane/iris/generation/bake/ChunkBakeCache.java b/core/src/main/java/art/arcane/iris/generation/bake/ChunkBakeCache.java index 2344e03fe..999848025 100644 --- a/core/src/main/java/art/arcane/iris/generation/bake/ChunkBakeCache.java +++ b/core/src/main/java/art/arcane/iris/generation/bake/ChunkBakeCache.java @@ -10,6 +10,7 @@ public final class ChunkBakeCache implements BakeCache { private static final ThreadLocal SPARSE = ThreadLocal.withInitial(() -> new int[1]); private final PlaneSource source; + private final ThreadLocal recent = ThreadLocal.withInitial(Recent::new); private volatile ConcurrentClockCache entries; public ChunkBakeCache(PlaneSource source, int capacityChunks) { @@ -43,7 +44,9 @@ public final class ChunkBakeCache implements BakeCache { } public void clear() { - entries.clear(); + ConcurrentClockCache current = entries; + entries = new ConcurrentClockCache<>(current.capacity()); + current.clear(); } public long[] census() { @@ -71,8 +74,22 @@ public final class ChunkBakeCache implements BakeCache { } public ChunkPlanes.Plane planeIfPresent(BakePlane plane, int chunkX, int chunkZ) { - ChunkPlanes planes = entries.get(key(chunkX, chunkZ)); - return planes == null ? null : planes.planeIfPresent(plane); + long key = key(chunkX, chunkZ); + Recent last = recent.get(); + ConcurrentClockCache current = entries; + ChunkPlanes planes; + if (last.key == key && last.entries == current) { + planes = last.planes; + } else { + planes = current.get(key); + if (planes == null) { + return null; + } + last.key = key; + last.planes = planes; + last.entries = current; + } + return planes.planeIfPresent(plane); } public ChunkPlanes.Plane plane(BakePlane plane, int chunkX, int chunkZ) { @@ -80,7 +97,7 @@ public final class ChunkBakeCache implements BakeCache { } public Object complete(BakePlane plane, int chunkX, int chunkZ) { - return planes(chunkX, chunkZ).complete(plane, source); + return remembered(chunkX, chunkZ).complete(plane, source); } public boolean memoAllowed() { @@ -91,14 +108,26 @@ public final class ChunkBakeCache implements BakeCache { if (revision != ProvisionalSampling.revision()) { return; } - planes(blockX >> 4, blockZ >> 4).plane(plane).storeDouble(((blockZ & 15) << 4) | (blockX & 15), value); + remembered(blockX >> 4, blockZ >> 4).plane(plane).storeDouble(((blockZ & 15) << 4) | (blockX & 15), value); } public void storeObject(BakePlane plane, int blockX, int blockZ, Object value, long revision) { if (revision != ProvisionalSampling.revision()) { return; } - planes(blockX >> 4, blockZ >> 4).plane(plane).storeObject(((blockZ & 15) << 4) | (blockX & 15), value); + remembered(blockX >> 4, blockZ >> 4).plane(plane).storeObject(((blockZ & 15) << 4) | (blockX & 15), value); + } + + private ChunkPlanes remembered(int chunkX, int chunkZ) { + ConcurrentClockCache current = entries; + long key = key(chunkX, chunkZ); + ChunkPlanes existing = current.get(key); + ChunkPlanes planes = existing != null ? existing : current.putIfAbsent(key, new ChunkPlanes(chunkX, chunkZ)); + Recent last = recent.get(); + last.key = key; + last.planes = planes; + last.entries = current; + return planes; } public static T sparse(Supplier action) { @@ -125,4 +154,10 @@ public final class ChunkBakeCache implements BakeCache { public static long key(int chunkX, int chunkZ) { return ((long) chunkX << 32) ^ (chunkZ & 0xffffffffL); } + + private static final class Recent { + private long key; + private ChunkPlanes planes; + private ConcurrentClockCache entries; + } } diff --git a/core/src/main/java/art/arcane/iris/generation/noise/GeneratorProgram.java b/core/src/main/java/art/arcane/iris/generation/noise/GeneratorProgram.java index bd3c76c72..233a7fd3a 100644 --- a/core/src/main/java/art/arcane/iris/generation/noise/GeneratorProgram.java +++ b/core/src/main/java/art/arcane/iris/generation/noise/GeneratorProgram.java @@ -69,6 +69,12 @@ public final class GeneratorProgram { double[] fractionZ = scratch.buffer(count); scratch.clearLattice(count * 4); int detailed = 0; + double previousX = Double.NaN; + double previousZ = Double.NaN; + int cellNorthWest = -1; + int cellNorthEast = -1; + int cellSouthWest = -1; + int cellSouthEast = -1; for (int index = 0; index < count; index++) { double lowerX = Math.floor(xs[index] / SURFACE_GRID) * SURFACE_GRID; double lowerZ = Math.floor(zs[index] / SURFACE_GRID) * SURFACE_GRID; @@ -76,10 +82,28 @@ public final class GeneratorProgram { double dz = (zs[index] - lowerZ) / SURFACE_GRID; fractionX[index] = dx; fractionZ[index] = dz; - northWest[index] = scratch.lattice(lowerX, lowerZ); - northEast[index] = dx == 0D ? -1 : scratch.lattice(lowerX + SURFACE_GRID, lowerZ); - southWest[index] = dz == 0D ? -1 : scratch.lattice(lowerX, lowerZ + SURFACE_GRID); - southEast[index] = dx == 0D || dz == 0D ? -1 : scratch.lattice(lowerX + SURFACE_GRID, lowerZ + SURFACE_GRID); + if (Double.doubleToRawLongBits(lowerX) != Double.doubleToRawLongBits(previousX) + || Double.doubleToRawLongBits(lowerZ) != Double.doubleToRawLongBits(previousZ)) { + previousX = lowerX; + previousZ = lowerZ; + cellNorthWest = scratch.lattice(lowerX, lowerZ); + cellNorthEast = -1; + cellSouthWest = -1; + cellSouthEast = -1; + } + if (dx != 0D && cellNorthEast < 0) { + cellNorthEast = scratch.lattice(lowerX + SURFACE_GRID, lowerZ); + } + if (dz != 0D && cellSouthWest < 0) { + cellSouthWest = scratch.lattice(lowerX, lowerZ + SURFACE_GRID); + } + if (dx != 0D && dz != 0D && cellSouthEast < 0) { + cellSouthEast = scratch.lattice(lowerX + SURFACE_GRID, lowerZ + SURFACE_GRID); + } + northWest[index] = cellNorthWest; + northEast[index] = dx == 0D ? -1 : cellNorthEast; + southWest[index] = dz == 0D ? -1 : cellSouthWest; + southEast[index] = dx == 0D || dz == 0D ? -1 : cellSouthEast; if (dx != 0D || dz != 0D) { detailed++; }