From ae1a84702ccac1ad2939561785d6c69b65a3dfc2 Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Thu, 22 Oct 2026 04:08:14 -0400 Subject: [PATCH] Scratch resets and gated counters - Terrain batch scratch marks reset in finally blocks so a failing kernel cannot grow the scratch - Generator evaluation counters only count when generation counters are enabled - Core tests run with generation counters enabled --- core/build.gradle | 1 + .../generation/bake/GeneratorEvaluations.java | 11 ++++ .../iris/generation/bake/TerrainProgram.java | 13 ++++- .../generation/noise/GeneratorProgram.java | 44 ++++++++++++--- .../generation/noise/NoiseLayerProgram.java | 56 +++++++++++++------ 5 files changed, 95 insertions(+), 30 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 457e53dff..091338be7 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -178,6 +178,7 @@ dependencies { tasks.named('test').configure { maxHeapSize = '1g' jvmArgs('-XX:+ExitOnOutOfMemoryError') + systemProperty('iris.generation.counters', 'true') } java { diff --git a/core/src/main/java/art/arcane/iris/generation/bake/GeneratorEvaluations.java b/core/src/main/java/art/arcane/iris/generation/bake/GeneratorEvaluations.java index 7466bed71..9cc9de400 100644 --- a/core/src/main/java/art/arcane/iris/generation/bake/GeneratorEvaluations.java +++ b/core/src/main/java/art/arcane/iris/generation/bake/GeneratorEvaluations.java @@ -1,5 +1,7 @@ package art.arcane.iris.generation.bake; +import art.arcane.iris.generation.runtime.GenerationCounter; + import java.util.concurrent.atomic.LongAdder; public final class GeneratorEvaluations { @@ -12,15 +14,24 @@ public final class GeneratorEvaluations { } public static void bakedChunk(long evaluations) { + if (!GenerationCounter.ENABLED) { + return; + } BAKED_CHUNKS.increment(); BAKED.add(evaluations); } public static void batched(long evaluations) { + if (!GenerationCounter.ENABLED) { + return; + } BATCHED.add(evaluations); } public static void scalar(int evaluations) { + if (!GenerationCounter.ENABLED) { + return; + } SCALAR.add(evaluations); } diff --git a/core/src/main/java/art/arcane/iris/generation/bake/TerrainProgram.java b/core/src/main/java/art/arcane/iris/generation/bake/TerrainProgram.java index a67f63719..938922c3d 100644 --- a/core/src/main/java/art/arcane/iris/generation/bake/TerrainProgram.java +++ b/core/src/main/java/art/arcane/iris/generation/bake/TerrainProgram.java @@ -85,6 +85,16 @@ public final class TerrainProgram { } int mark = scratch.mark(); int indexMark = scratch.indexMark(); + try { + return accumulate(members, group, scratch, xs, zs, count, lows, highs, heights); + } finally { + scratch.reset(mark); + scratch.resetIndices(indexMark); + } + } + + private long accumulate(IrisGenerator[] members, int group, TerrainBatchScratch scratch, double[] xs, double[] zs, + int count, double[] lows, double[] highs, double[] heights) { int[] modes = scratch.indices(count); int activeCount = 0; for (int index = 0; index < count; index++) { @@ -111,7 +121,6 @@ public final class TerrainProgram { activeCount++; } if (activeCount == 0) { - scratch.resetIndices(indexMark); return 0L; } double[] activeX = scratch.buffer(activeCount); @@ -154,8 +163,6 @@ public final class TerrainProgram { for (int index = 0; index < activeCount; index++) { heights[activeIndex[index]] += sums[index] / members.length; } - scratch.reset(mark); - scratch.resetIndices(indexMark); return (long) activeCount * members.length; } } 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 360746480..9d6cc266c 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 @@ -91,10 +91,15 @@ public final class GeneratorProgram { return sample(scratch, x, z); } int mark = scratch.mark(); - double[] cached = scratch.buffer(1); - boolean hit = IrisGenerator.cachedSurface(stripes, x, z, superSeed, cached, 0); - double value = cached[0]; - scratch.reset(mark); + boolean hit; + double value; + try { + double[] cached = scratch.buffer(1); + hit = IrisGenerator.cachedSurface(stripes, x, z, superSeed, cached, 0); + value = cached[0]; + } finally { + scratch.reset(mark); + } if (hit) { return value; } @@ -125,6 +130,15 @@ public final class GeneratorProgram { private void surfaceHeights(TerrainBatchScratch scratch, double[] xs, double[] zs, int count, double[] out) { int mark = scratch.mark(); int indexMark = scratch.indexMark(); + try { + fillSurfaceHeights(scratch, xs, zs, count, out); + } finally { + scratch.resetIndices(indexMark); + scratch.reset(mark); + } + } + + private void fillSurfaceHeights(TerrainBatchScratch scratch, double[] xs, double[] zs, int count, double[] out) { int[] northWest = scratch.indices(count); int[] northEast = scratch.indices(count); int[] southWest = scratch.indices(count); @@ -209,14 +223,21 @@ public final class GeneratorProgram { } out[index] = surfaceDetail == 0D ? smooth : smooth + (detail[detailIndex[index]] - smooth) * surfaceDetail; } - scratch.resetIndices(indexMark); - scratch.reset(mark); } private void resolveLattice(TerrainBatchScratch scratch, int nodes, double[] lattice) { IrisGenerator.SurfaceCacheStripe[] stripes = generator.surfaceStripes(); int indexMark = scratch.indexMark(); int mark = scratch.mark(); + try { + fillLattice(scratch, nodes, lattice, stripes); + } finally { + scratch.reset(mark); + scratch.resetIndices(indexMark); + } + } + + private void fillLattice(TerrainBatchScratch scratch, int nodes, double[] lattice, IrisGenerator.SurfaceCacheStripe[] stripes) { int[] missing = scratch.indices(nodes); double[] missingX = scratch.buffer(nodes); double[] missingZ = scratch.buffer(nodes); @@ -242,12 +263,18 @@ public final class GeneratorProgram { } } } - scratch.reset(mark); - scratch.resetIndices(indexMark); } private void sample(TerrainBatchScratch scratch, double[] xs, double[] zs, int count, double[] out) { int mark = scratch.mark(); + try { + sampleBatch(scratch, xs, zs, count, out); + } finally { + scratch.reset(mark); + } + } + + private void sampleBatch(TerrainBatchScratch scratch, double[] xs, double[] zs, int count, double[] out) { double[] sampleX = scratch.buffer(count); double[] sampleZ = scratch.buffer(count); double[] noise = scratch.buffer(count); @@ -284,6 +311,5 @@ public final class GeneratorProgram { out[index] = generator.cell(xs[index], zs[index], out[index], 0D); } } - scratch.reset(mark); } } diff --git a/core/src/main/java/art/arcane/iris/generation/noise/NoiseLayerProgram.java b/core/src/main/java/art/arcane/iris/generation/noise/NoiseLayerProgram.java index e9bd1df41..c5528d10a 100644 --- a/core/src/main/java/art/arcane/iris/generation/noise/NoiseLayerProgram.java +++ b/core/src/main/java/art/arcane/iris/generation/noise/NoiseLayerProgram.java @@ -52,6 +52,14 @@ public final class NoiseLayerProgram { return; } int mark = scratch.mark(); + try { + fill(scratch, xs, zs, count, out); + } finally { + scratch.reset(mark); + } + } + + private void fill(TerrainBatchScratch scratch, double[] xs, double[] zs, int count, double[] out) { double[] sampleX = scratch.buffer(count); double[] sampleZ = scratch.buffer(count); if (children.length == 0) { @@ -81,7 +89,6 @@ public final class NoiseLayerProgram { for (int index = 0; index < count; index++) { out[index] = post(out[index]); } - scratch.reset(mark); } void evaluatePair(TerrainBatchScratch scratch, double[] xs, double[] zs, int count, double[] forward, double[] reverse) { @@ -91,6 +98,14 @@ public final class NoiseLayerProgram { return; } int mark = scratch.mark(); + try { + fillPair(scratch, xs, zs, count, forward, reverse); + } finally { + scratch.reset(mark); + } + } + + private void fillPair(TerrainBatchScratch scratch, double[] xs, double[] zs, int count, double[] forward, double[] reverse) { int pairs = count * 2; double[] sampleX = scratch.buffer(pairs); double[] sampleZ = scratch.buffer(pairs); @@ -122,7 +137,6 @@ public final class NoiseLayerProgram { forward[index] = post(values[index]); reverse[index] = post(values[count + index]); } - scratch.reset(mark); } public double sample(TerrainBatchScratch scratch, double x, double z) { @@ -133,14 +147,17 @@ public final class NoiseLayerProgram { double sampleZ = z; if (children.length > 0) { int mark = scratch.mark(); - double[] pair = scratch.buffer(2); - for (int child = 0; child < children.length; child++) { - children[child].samplePair(scratch, x, z, pair); - double offset = childOffsets[child]; - sampleX += pair[0] - offset; - sampleZ += pair[1] - offset; + try { + double[] pair = scratch.buffer(2); + for (int child = 0; child < children.length; child++) { + children[child].samplePair(scratch, x, z, pair); + double offset = childOffsets[child]; + sampleX += pair[0] - offset; + sampleZ += pair[1] - offset; + } + } finally { + scratch.reset(mark); } - scratch.reset(mark); } return post(program.sample2D((sampleX / zoom) + offsetX, (sampleZ / zoom) + offsetZ)); } @@ -157,16 +174,19 @@ public final class NoiseLayerProgram { double reverseZ = x; if (children.length > 0) { int mark = scratch.mark(); - double[] pair = scratch.buffer(2); - for (int child = 0; child < children.length; child++) { - children[child].samplePair(scratch, x, z, pair); - double offset = childOffsets[child]; - forwardX += pair[0] - offset; - forwardZ += pair[1] - offset; - reverseX += pair[1] - offset; - reverseZ += pair[0] - offset; + try { + double[] pair = scratch.buffer(2); + for (int child = 0; child < children.length; child++) { + children[child].samplePair(scratch, x, z, pair); + double offset = childOffsets[child]; + forwardX += pair[0] - offset; + forwardZ += pair[1] - offset; + reverseX += pair[1] - offset; + reverseZ += pair[0] - offset; + } + } finally { + scratch.reset(mark); } - scratch.reset(mark); } out[0] = post(program.sample2D((forwardX / zoom) + offsetX, (forwardZ / zoom) + offsetZ)); out[1] = post(program.sample2D((reverseX / zoom) + offsetX, (reverseZ / zoom) + offsetZ));