mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-17 22:14:56 +00:00
Remove the 2D cache bypass
Hydrology sampling now goes through the engine 2D caches; the thread-local bypass and its test are gone.
This commit is contained in:
+3
-7
@@ -95,13 +95,9 @@ public final class IrisHydrologyRuntime implements AutoCloseable {
|
||||
this.settings = createSettings(context.dimension(), hydrology);
|
||||
HydrologyGeometrySampler geometrySampler = geometrySampler(context, hydrology);
|
||||
IrisHydrologyRoutingTerrainSampler.Sources terrainSources = new IrisHydrologyRoutingTerrainSampler.Sources(
|
||||
(int x, int z, double rawNaturalHeight) -> ProceduralStream.bypass2DCaches(
|
||||
() -> createTerrainBasis(x, z, rawNaturalHeight)
|
||||
),
|
||||
this::createTerrainBasis,
|
||||
(int x, int z) -> context.naturalHeightProvider().sample(x, z),
|
||||
(int x, int z) -> ProceduralStream.bypass2DCaches(
|
||||
() -> context.naturalOceanClassifier().isOcean(x, z)
|
||||
)
|
||||
(int x, int z) -> context.naturalOceanClassifier().isOcean(x, z)
|
||||
);
|
||||
this.routingTerrainSampler = new IrisHydrologyRoutingTerrainSampler(
|
||||
terrainSources,
|
||||
@@ -370,7 +366,7 @@ public final class IrisHydrologyRuntime implements AutoCloseable {
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
HydrologyTerrainSample sampled = ProceduralStream.bypass2DCaches(() -> createDetailedTerrainSample(x, z));
|
||||
HydrologyTerrainSample sampled = createDetailedTerrainSample(x, z);
|
||||
synchronized (terrainSampleLock) {
|
||||
HydrologyTerrainSample existing = terrainSamples.get(packed);
|
||||
if (existing != null) {
|
||||
|
||||
@@ -72,18 +72,9 @@ import art.arcane.iris.util.project.stream.utility.SynchronizedStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@SuppressWarnings("ALL")
|
||||
public interface ProceduralStream<T> extends ProceduralLayer, Interpolated<T> {
|
||||
static <V> V bypass2DCaches(Supplier<V> operation) {
|
||||
return ProceduralStreamCacheBypass.supply(operation);
|
||||
}
|
||||
|
||||
static boolean is2DCacheBypassActive() {
|
||||
return ProceduralStreamCacheBypass.isActive();
|
||||
}
|
||||
|
||||
static ProceduralStream<Double> ofDouble(Function2<Double, Double, Double> f) {
|
||||
try {
|
||||
return of(f, Interpolated.DOUBLE);
|
||||
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
package art.arcane.iris.util.project.stream;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
final class ProceduralStreamCacheBypass {
|
||||
private static final ThreadLocal<Integer> DEPTH = new ThreadLocal<>();
|
||||
|
||||
private ProceduralStreamCacheBypass() {
|
||||
}
|
||||
|
||||
static boolean isActive() {
|
||||
return DEPTH.get() != null;
|
||||
}
|
||||
|
||||
static <T> T supply(Supplier<T> operation) {
|
||||
Integer previousDepth = DEPTH.get();
|
||||
DEPTH.set(previousDepth == null ? 1 : previousDepth + 1);
|
||||
try {
|
||||
return operation.get();
|
||||
} finally {
|
||||
if (previousDepth == null) {
|
||||
DEPTH.remove();
|
||||
} else {
|
||||
DEPTH.set(previousDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-6
@@ -34,9 +34,6 @@ public class CachedDoubleStream2D extends BasicStream<Double> implements Procedu
|
||||
|
||||
@Override
|
||||
public Double get(double x, double z) {
|
||||
if (ProceduralStream.is2DCacheBypassActive()) {
|
||||
return stream.getDouble((int) x, (int) z);
|
||||
}
|
||||
return cache.get((int) x, (int) z);
|
||||
}
|
||||
|
||||
@@ -47,9 +44,6 @@ public class CachedDoubleStream2D extends BasicStream<Double> implements Procedu
|
||||
|
||||
@Override
|
||||
public double getDouble(double x, double z) {
|
||||
if (ProceduralStream.is2DCacheBypassActive()) {
|
||||
return stream.getDouble((int) x, (int) z);
|
||||
}
|
||||
return cache.get((int) x, (int) z);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,9 +55,6 @@ public class CachedStream2D<T> extends BasicStream<T> implements ProceduralStrea
|
||||
|
||||
@Override
|
||||
public T get(double x, double z) {
|
||||
if (ProceduralStream.is2DCacheBypassActive()) {
|
||||
return stream.get((int) x, (int) z);
|
||||
}
|
||||
return cache.get((int) x, (int) z);
|
||||
}
|
||||
|
||||
|
||||
-173
@@ -1,173 +0,0 @@
|
||||
package art.arcane.iris.util.project.stream;
|
||||
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.framework.MeteredCache;
|
||||
import art.arcane.iris.engine.framework.PreservationRegistry;
|
||||
import art.arcane.iris.spi.IrisServices;
|
||||
import art.arcane.iris.util.project.stream.interpolation.Interpolated;
|
||||
import art.arcane.iris.util.project.stream.utility.CachedDoubleStream2D;
|
||||
import art.arcane.iris.util.project.stream.utility.CachedStream2D;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class ProceduralStreamCacheBypassTest {
|
||||
private PreservationRegistry previousRegistry;
|
||||
private Engine engine;
|
||||
|
||||
@Before
|
||||
public void registerPreservationService() {
|
||||
previousRegistry = IrisServices.getOrNull(PreservationRegistry.class);
|
||||
IrisServices.register(PreservationRegistry.class, new NoOpPreservationRegistry());
|
||||
engine = mock(Engine.class);
|
||||
}
|
||||
|
||||
@After
|
||||
public void restorePreservationService() {
|
||||
if (previousRegistry == null) {
|
||||
IrisServices.remove(PreservationRegistry.class);
|
||||
} else {
|
||||
IrisServices.register(PreservationRegistry.class, previousRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalAccessCachesIntegerQuantizedValues() {
|
||||
AtomicInteger genericCalls = new AtomicInteger();
|
||||
ProceduralStream<Integer> genericSource = ProceduralStream.of(
|
||||
(x, z) -> genericCalls.incrementAndGet(),
|
||||
Interpolated.INT
|
||||
);
|
||||
CachedStream2D<Integer> genericCache = new CachedStream2D<>("generic", engine, genericSource, 8);
|
||||
|
||||
assertEquals(Integer.valueOf(1), genericCache.get(12.9D, -3.9D));
|
||||
assertEquals(Integer.valueOf(1), genericCache.get(12.1D, -3.1D));
|
||||
assertEquals(1, genericCalls.get());
|
||||
assertEquals(256L, genericCache.getSize());
|
||||
|
||||
AtomicInteger doubleCalls = new AtomicInteger();
|
||||
ProceduralStream<Double> doubleSource = ProceduralStream.ofDouble((x, z) -> {
|
||||
doubleCalls.incrementAndGet();
|
||||
return x * 31D + z;
|
||||
});
|
||||
CachedDoubleStream2D doubleCache = new CachedDoubleStream2D("double", engine, doubleSource, 8);
|
||||
|
||||
assertEquals(-1_026D, doubleCache.getDouble(-33.9D, -3.9D), 0D);
|
||||
assertEquals(-1_026D, doubleCache.getDouble(-33.1D, -3.1D), 0D);
|
||||
assertEquals(1, doubleCalls.get());
|
||||
assertEquals(256L, doubleCache.getSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bypassMatchesNestedTwoDimensionalSemanticsWithoutGrowingCaches() {
|
||||
DoubleChain baseline = new DoubleChain(engine);
|
||||
DoubleChain bypassed = new DoubleChain(engine);
|
||||
for (int index = 0; index < 32; index++) {
|
||||
double x = index * 64D + 4.875D;
|
||||
double z = index * -96D + 5.625D;
|
||||
double expected = baseline.output.get(x, z);
|
||||
double actual = ProceduralStream.bypass2DCaches(() -> bypassed.output.get(x, z));
|
||||
assertEquals(Double.doubleToLongBits(expected), Double.doubleToLongBits(actual));
|
||||
}
|
||||
|
||||
assertEquals(2_048L, baseline.inner.getSize());
|
||||
assertEquals(2_048L, baseline.converted.getSize());
|
||||
assertEquals(2_048L, baseline.output.getSize());
|
||||
assertEquals(0L, bypassed.inner.getSize());
|
||||
assertEquals(0L, bypassed.converted.getSize());
|
||||
assertEquals(0L, bypassed.output.getSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedScopesRestoreAfterExceptions() {
|
||||
DoubleChain chain = new DoubleChain(engine);
|
||||
|
||||
ProceduralStream.bypass2DCaches(() -> {
|
||||
assertThrows(IllegalStateException.class, () -> ProceduralStream.bypass2DCaches(() -> {
|
||||
chain.output.getDouble(3_000.75D, -4_000.25D);
|
||||
throw new IllegalStateException("expected");
|
||||
}));
|
||||
chain.output.getDouble(5_000.75D, -6_000.25D);
|
||||
assertEquals(0L, chain.inner.getSize());
|
||||
assertEquals(0L, chain.converted.getSize());
|
||||
assertEquals(0L, chain.output.getSize());
|
||||
return null;
|
||||
});
|
||||
|
||||
chain.output.getDouble(7_000.75D, -8_000.25D);
|
||||
assertEquals(256L, chain.inner.getSize());
|
||||
assertEquals(256L, chain.converted.getSize());
|
||||
assertEquals(256L, chain.output.getSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bypassIsThreadLocal() {
|
||||
CachedDoubleStream2D cache = new CachedDoubleStream2D(
|
||||
"thread-local",
|
||||
engine,
|
||||
ProceduralStream.ofDouble((x, z) -> x * 17D + z),
|
||||
8
|
||||
);
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
try {
|
||||
ProceduralStream.bypass2DCaches(() -> {
|
||||
CompletableFuture<Double> otherThread = CompletableFuture.supplyAsync(
|
||||
() -> cache.getDouble(1_024.75D, 2_048.25D),
|
||||
executor
|
||||
);
|
||||
assertEquals(19_456D, otherThread.join(), 0D);
|
||||
assertEquals(256L, cache.getSize());
|
||||
cache.getDouble(4_096.75D, 8_192.25D);
|
||||
assertEquals(256L, cache.getSize());
|
||||
return null;
|
||||
});
|
||||
cache.getDouble(12_288.75D, 16_384.25D);
|
||||
assertEquals(512L, cache.getSize());
|
||||
} finally {
|
||||
executor.shutdownNow();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DoubleChain {
|
||||
private final CachedDoubleStream2D inner;
|
||||
private final CachedStream2D<Double> converted;
|
||||
private final CachedDoubleStream2D output;
|
||||
|
||||
private DoubleChain(Engine engine) {
|
||||
ProceduralStream<Double> source = ProceduralStream.ofDouble(
|
||||
(x, z) -> x * x * 0.125D + z * z * 0.25D + x * z * 0.0625D
|
||||
);
|
||||
inner = new CachedDoubleStream2D("inner", engine, source, 8);
|
||||
ProceduralStream<Double> conversion = inner.convert(value -> value * 1.25D - 7D);
|
||||
converted = new CachedStream2D<>("converted", engine, conversion, 8);
|
||||
output = new CachedDoubleStream2D("output", engine, converted.slope(3), 8);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class NoOpPreservationRegistry implements PreservationRegistry {
|
||||
@Override
|
||||
public void register(Thread thread) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(ExecutorService service) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCache(MeteredCache cache) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dereference() {
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user