Missing section misdirection

- Avoid adding all sections every frame
- Remove sections when they are no longer needed
- Rebuild the lut when sections are removed
- Properly detect missing sections by writing 1-based indices to the lut
This commit is contained in:
Jozufozu 2024-06-29 19:01:48 -07:00
parent cf2c11a37c
commit 2a0694ccaf
5 changed files with 50 additions and 16 deletions

View file

@ -46,7 +46,8 @@ public class EngineImpl implements Engine {
@Override
public Plan<RenderContext> createFramePlan() {
return lightStorage.createFramePlan().then(SyncedPlan.of(this::flush));
return lightStorage.createFramePlan()
.then(SyncedPlan.of(this::flush));
}
@Override

View file

@ -80,7 +80,8 @@ public class LightLut {
zLookup.ensureCapacity(zIndex + 3);
zLookup.size(zIndex + 3);
}
zLookup.set(zIndex + 2, sectionIndicesMaps.get(position));
// Add 1 to the actual index so that 0 indicates a missing section.
zLookup.set(zIndex + 2, sectionIndicesMaps.get(position) + 1);
}
return indices;
}

View file

@ -12,6 +12,7 @@ import dev.engine_room.flywheel.lib.task.SimplePlan;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.longs.Long2IntMap;
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.LevelAccessor;
@ -47,7 +48,7 @@ public class LightStorage {
}
private final BitSet changed = new BitSet();
private boolean newSections = false;
private boolean needsLutRebuild = false;
public LightStorage(LevelAccessor level, EnvironmentStorage environmentStorage) {
this.level = level;
@ -58,11 +59,34 @@ public class LightStorage {
public Plan<RenderContext> createFramePlan() {
return SimplePlan.of(() -> {
var longs = environmentStorage.allLightSections();
longs.forEach(this::addSection);
var allLightSections = environmentStorage.allLightSections();
removeUnusedSections(allLightSections);
// Only add the new sections.
allLightSections.removeAll(section2ArenaIndex.keySet());
for (var section : allLightSections) {
addSection(section);
}
});
}
private void removeUnusedSections(LongSet allLightSections) {
var entries = section2ArenaIndex.long2IntEntrySet();
var it = entries.iterator();
while (it.hasNext()) {
var entry = it.next();
var section = entry.getLongKey();
if (!allLightSections.contains(section)) {
arena.free(entry.getIntValue());
needsLutRebuild = true;
it.remove();
}
}
}
public int capacity() {
return arena.capacity();
}
@ -179,15 +203,11 @@ public class LightStorage {
if (out == INVALID_SECTION) {
out = arena.alloc();
section2ArenaIndex.put(section, out);
newSections = true;
needsLutRebuild = true;
}
return out;
}
public void removeSection(long section) {
}
public void delete() {
arena.delete();
}
@ -196,8 +216,10 @@ public class LightStorage {
return !changed.isEmpty();
}
public boolean hasNewSections() {
return newSections;
public boolean checkNeedsLutRebuildAndClear() {
var out = needsLutRebuild;
needsLutRebuild = false;
return out;
}
public void uploadChangedSections(StagingBuffer staging, int dstVbo) {
@ -208,6 +230,7 @@ public class LightStorage {
}
public IntArrayList createLut() {
// TODO: incremental lut updates
return LightLut.buildLut(section2ArenaIndex);
}
}

View file

@ -22,7 +22,7 @@ public class LightBuffers {
lightArena.ensureCapacity(capacity);
light.uploadChangedSections(staging, lightArena.handle());
if (light.hasNewSections()) {
if (light.checkNeedsLutRebuildAndClear()) {
var lut = light.createLut();
this.lut.ensureCapacity(lut.size());

View file

@ -42,15 +42,24 @@ bool _flw_nextLut(uint base, int coord, out uint next) {
bool _flw_chunkCoordToSectionIndex(ivec3 sectionPos, out uint index) {
uint y;
if (_flw_nextLut(0, sectionPos.x, y)) {
if (_flw_nextLut(0, sectionPos.x, y) || y == 0) {
return true;
}
uint z;
if (_flw_nextLut(y, sectionPos.y, z)) {
if (_flw_nextLut(y, sectionPos.y, z) || z == 0) {
return true;
}
return _flw_nextLut(z, sectionPos.z, index);
uint sectionIndex;
if (_flw_nextLut(z, sectionPos.z, index) || index == 0) {
return true;
}
// The index is written as 1-based so we can properly detect missing sections.
index = sectionIndex - 1;
return false;
}
vec2 _flw_lightAt(uint sectionOffset, uvec3 blockInSectionPos) {