From bedb92c73c9bea114d8dea44db3ddcbf7677b065 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Sun, 10 Nov 2024 11:59:05 -0800 Subject: [PATCH] Lessen updates today! - LightLut now does incremental updates java-side - Still requires a full upload when changed, though it does not take up much space - ShaderLightVisualStorage now actually triggers removal of light section from the lut --- .../flywheel/backend/engine/LightLut.java | 87 +++++++++++++------ .../flywheel/backend/engine/LightStorage.java | 28 +++--- .../storage/ShaderLightVisualStorage.java | 6 +- 3 files changed, 85 insertions(+), 36 deletions(-) diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightLut.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightLut.java index d17ed806d..300d47da4 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightLut.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightLut.java @@ -3,17 +3,16 @@ package dev.engine_room.flywheel.backend.engine; import java.util.function.BiConsumer; import java.util.function.Supplier; +import org.jetbrains.annotations.Nullable; + import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.longs.Long2IntMap; import net.minecraft.core.SectionPos; +// Massive kudos to RogueLogix for figuring out this LUT scheme. public final class LightLut { private final Layer> indices = new Layer<>(); - private LightLut() { - } - - private void add(long position, int index) { + public void add(long position, int index) { final var x = SectionPos.x(position); final var y = SectionPos.y(position); final var z = SectionPos.z(position); @@ -23,31 +22,32 @@ public final class LightLut { .set(z, index + 1); } - private IntArrayList toLut() { + public void remove(long section) { + final var x = SectionPos.x(section); + final var y = SectionPos.y(section); + final var z = SectionPos.z(section); + + var first = indices.get(x); + + if (first == null) { + return; + } + + var second = first.get(y); + + if (second == null) { + return; + } + + second.clear(z); + } + + public IntArrayList flatten() { final var out = new IntArrayList(); indices.fillLut(out, (yIndices, lut) -> yIndices.fillLut(lut, IntLayer::fillLut)); return out; } - // Massive kudos to RogueLogix for figuring out this LUT scheme. - // TODO: switch to y x z or x z y ordering - // DATA LAYOUT - // [0] : base chunk X, X index count, followed by linear indices of y blocks - // [yBlockIndex] : baseChunk Y, Y index count, followed by linear indices of z blocks for this x - // [zBlockIndex] : baseChunk Z, Z index count, followed by linear indices of lighting chunks - // this data layout allows a single buffer to represent the lighting volume, without requiring the entire 3d lookup volume to be allocated - public static IntArrayList buildLut(Long2IntMap sectionIndicesMaps) { - if (sectionIndicesMaps.isEmpty()) { - return new IntArrayList(); - } - - var out = new LightLut(); - - sectionIndicesMaps.forEach(out::add); - - return out.toLut(); - } - private static final class Layer { private boolean hasBase = false; private int base = 0; @@ -78,6 +78,25 @@ public final class LightLut { } } + @Nullable + public T get(int i) { + if (!hasBase) { + return null; + } + + if (i < base) { + return null; + } + + final var offset = i - base; + + if (offset >= nextLayer.length) { + return null; + } + + return (T) nextLayer[offset]; + } + public T computeIfAbsent(int i, Supplier ifAbsent) { if (!hasBase) { // We don't want to default to base 0, so we'll use the first value we get. @@ -155,6 +174,24 @@ public final class LightLut { indices[offset] = index; } + public void clear(int i) { + if (!hasBase) { + return; + } + + if (i < base) { + return; + } + + final var offset = i - base; + + if (offset >= indices.length) { + return; + } + + indices[offset] = 0; + } + private void resize(int length) { final var newIndices = new int[length]; System.arraycopy(indices, 0, newIndices, 0, indices.length); diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightStorage.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightStorage.java index 5b5ac1d51..f8b91be89 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightStorage.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/LightStorage.java @@ -44,12 +44,9 @@ public class LightStorage { private static final int INVALID_SECTION = -1; private final LevelAccessor level; - + private final LightLut lut; private final CpuArena arena; - private final Long2IntMap section2ArenaIndex = new Long2IntOpenHashMap(); - { - section2ArenaIndex.defaultReturnValue(INVALID_SECTION); - } + private final Long2IntMap section2ArenaIndex; private final BitSet changed = new BitSet(); private boolean needsLutRebuild = false; @@ -60,8 +57,10 @@ public class LightStorage { public LightStorage(LevelAccessor level) { this.level = level; - + lut = new LightLut(); arena = new CpuArena(SECTION_SIZE_BYTES, DEFAULT_ARENA_CAPACITY_SECTIONS); + section2ArenaIndex = new Long2IntOpenHashMap(); + section2ArenaIndex.defaultReturnValue(INVALID_SECTION); } /** @@ -135,12 +134,22 @@ public class LightStorage { if (!requestedSections.contains(section)) { arena.free(entry.getIntValue()); - needsLutRebuild = true; + endTrackingSection(section); it.remove(); } } } + private void beginTrackingSection(long section, int index) { + lut.add(section, index); + needsLutRebuild = true; + } + + private void endTrackingSection(long section) { + lut.remove(section); + needsLutRebuild = true; + } + public int capacity() { return arena.capacity(); } @@ -374,7 +383,7 @@ public class LightStorage { if (out == INVALID_SECTION) { out = arena.alloc(); section2ArenaIndex.put(section, out); - needsLutRebuild = true; + beginTrackingSection(section, out); } return out; } @@ -406,8 +415,7 @@ public class LightStorage { } public IntArrayList createLut() { - // TODO: incremental lut updates - return LightLut.buildLut(section2ArenaIndex); + return lut.flatten(); } private enum SectionEdge { diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/ShaderLightVisualStorage.java b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/ShaderLightVisualStorage.java index 052a9e06c..804f98bae 100644 --- a/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/ShaderLightVisualStorage.java +++ b/common/src/main/java/dev/engine_room/flywheel/impl/visualization/storage/ShaderLightVisualStorage.java @@ -43,7 +43,11 @@ public class ShaderLightVisualStorage { } public void remove(ShaderLightVisual visual) { - trackers.remove(visual); + var tracker = trackers.remove(visual); + + if (tracker != null) { + markDirty(); + } } public void clear() {