stamps and notes

This commit is contained in:
mcrcortex
2025-05-02 23:44:49 +10:00
parent 917e308ece
commit fce99fbde3
4 changed files with 84 additions and 33 deletions

View File

@@ -4,18 +4,21 @@ import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
import me.cortex.voxy.common.world.WorldEngine; import me.cortex.voxy.common.world.WorldEngine;
import me.cortex.voxy.common.world.WorldSection; import me.cortex.voxy.common.world.WorldSection;
import java.util.concurrent.locks.StampedLock;
import java.util.function.LongConsumer; import java.util.function.LongConsumer;
import static me.cortex.voxy.common.world.WorldEngine.UPDATE_TYPE_BLOCK_BIT; import static me.cortex.voxy.common.world.WorldEngine.UPDATE_TYPE_BLOCK_BIT;
public class SectionUpdateRouter implements ISectionWatcher { public class SectionUpdateRouter implements ISectionWatcher {
private static final int SLICES = 1<<8; private static final int SLICES = 1<<4;
public interface IChildUpdate {void accept(WorldSection section);} public interface IChildUpdate {void accept(WorldSection section);}
private final Long2ByteOpenHashMap[] slices = new Long2ByteOpenHashMap[SLICES]; private final Long2ByteOpenHashMap[] slices = new Long2ByteOpenHashMap[SLICES];
private final StampedLock[] locks = new StampedLock[SLICES];
{ {
for (int i = 0; i < this.slices.length; i++) { for (int i = 0; i < this.slices.length; i++) {
this.slices[i] = new Long2ByteOpenHashMap(); this.slices[i] = new Long2ByteOpenHashMap();
this.locks[i] = new StampedLock();
} }
} }
@@ -35,17 +38,34 @@ public class SectionUpdateRouter implements ISectionWatcher {
} }
public boolean watch(long position, int types) { public boolean watch(long position, int types) {
var set = this.slices[getSliceIndex(position)]; int idx = getSliceIndex(position);
var set = this.slices[idx];
var lock = this.locks[idx];
byte delta = 0; byte delta = 0;
synchronized (set) { {
byte current = 0; long stamp = lock.readLock();
if (set.containsKey(position)) { byte current = set.getOrDefault(position, (byte) 0);
current = set.get(position);
}
delta = (byte) (current&types); delta = (byte) (current&types);
current |= (byte) types; current |= (byte) types;
delta ^= (byte) (current&types); delta ^= (byte) (current&types);
set.put(position, current); if (delta != 0) {//Was change
long ws = lock.tryConvertToWriteLock(stamp);
if (ws == 0) {
lock.unlockRead(stamp);
stamp = lock.writeLock();
//We need to recompute as we failed to acquire an immediate write lock
current = set.getOrDefault(position, (byte) 0);
delta = (byte) (current&types);
current |= (byte) types;
delta ^= (byte) (current&types);
if (delta != 0)
set.put(position, current);
} else {
stamp = ws;
set.put(position, current);
}
}
lock.unlock(stamp);
} }
if ((delta&UPDATE_TYPE_BLOCK_BIT)!=0) { if ((delta&UPDATE_TYPE_BLOCK_BIT)!=0) {
//If we added it, immediately invoke for an update //If we added it, immediately invoke for an update
@@ -58,38 +78,67 @@ public class SectionUpdateRouter implements ISectionWatcher {
return this.unwatch(WorldEngine.getWorldSectionId(lvl, x, y, z), types); return this.unwatch(WorldEngine.getWorldSectionId(lvl, x, y, z), types);
} }
public boolean unwatch(long position, int types) { public boolean unwatch(long position, int types) {//Types is types to unwatch
var set = this.slices[getSliceIndex(position)]; int idx = getSliceIndex(position);
synchronized (set) { var set = this.slices[idx];
if (!set.containsKey(position)) { var lock = this.locks[idx];
throw new IllegalStateException("Section pos not in map!! " + WorldEngine.pprintPos(position));
} long stamp = lock.readLock();
byte current = set.get(position);
byte delta = (byte) (current&types); byte current = set.getOrDefault(position, (byte)0);
current &= (byte) ~types; if (current == 0) {
if (current == 0) { throw new IllegalStateException("Section pos not in map " + WorldEngine.pprintPos(position));
set.remove(position);
return true;
}
set.put(position, current);
return false;
} }
boolean removed = false;
if ((current&types) != 0) {//Was change
long ws = lock.tryConvertToWriteLock(stamp);
if (ws == 0) {//failed to get write lock, need to unlock, get write, then redo
lock.unlockRead(stamp);
stamp = lock.writeLock();
current = set.getOrDefault(position, (byte)0);
if (current == 0) {
throw new IllegalStateException("Section pos not in map " + WorldEngine.pprintPos(position));
}
} else {
stamp = ws;
}
if ((current&types) != 0) {
current &= (byte) ~types;
if (current == 0) {
set.remove(position);
removed = true;
} else {
set.put(position, current);
}
}
}
lock.unlock(stamp);
return removed;
} }
public int get(long position) { public int get(long position) {
var set = this.slices[getSliceIndex(position)]; int idx = getSliceIndex(position);
synchronized (set) { var set = this.slices[idx];
return set.getOrDefault(position, (byte) 0); var lock = this.locks[idx];
} long stamp = lock.readLock();
int ret = set.getOrDefault(position, (byte) 0);
lock.unlockRead(stamp);
return ret;
} }
public void forwardEvent(WorldSection section, int type) { public void forwardEvent(WorldSection section, int type) {
final long position = section.key; final long position = section.key;
var set = this.slices[getSliceIndex(position)];
byte types = 0; int idx = getSliceIndex(position);
synchronized (set) { var set = this.slices[idx];
types = set.getOrDefault(position, (byte)0); var lock = this.locks[idx];
}
long stamp = lock.readLock();
byte types = set.getOrDefault(position, (byte) 0);
lock.unlockRead(stamp);
if (types!=0) { if (types!=0) {
if ((type&WorldEngine.UPDATE_TYPE_CHILD_EXISTENCE_BIT)!=0) { if ((type&WorldEngine.UPDATE_TYPE_CHILD_EXISTENCE_BIT)!=0) {
this.childUpdateCallback.accept(section); this.childUpdateCallback.accept(section);

View File

@@ -331,6 +331,7 @@ public class RenderDataFactory45 {
} }
} }
//TODO: add neighbor face culling
private void generateYZOpaqueInnerGeometry(int axis) { private void generateYZOpaqueInnerGeometry(int axis) {
for (int layer = 0; layer < 31; layer++) { for (int layer = 0; layer < 31; layer++) {
this.blockMesher.auxiliaryPosition = layer; this.blockMesher.auxiliaryPosition = layer;

View File

@@ -16,6 +16,7 @@ import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.function.LongConsumer; import java.util.function.LongConsumer;
//TODO: replace synchronize with StampedLock
public class MemoryStorageBackend extends StorageBackend { public class MemoryStorageBackend extends StorageBackend {
private final Long2ObjectMap<MemoryBuffer>[] maps; private final Long2ObjectMap<MemoryBuffer>[] maps;
private final Int2ObjectMap<ByteBuffer> idMappings = new Int2ObjectOpenHashMap<>(); private final Int2ObjectMap<ByteBuffer> idMappings = new Int2ObjectOpenHashMap<>();

View File

@@ -18,7 +18,7 @@ public class ActiveSectionTracker {
//Loaded section world cache, TODO: get rid of VolatileHolder and use something more sane //Loaded section world cache, TODO: get rid of VolatileHolder and use something more sane
private final Long2ObjectOpenHashMap<VolatileHolder<WorldSection>>[] loadedSectionCache; private final Long2ObjectOpenHashMap<VolatileHolder<WorldSection>>[] loadedSectionCache;
private final ReentrantLock[] locks; private final ReentrantLock[] locks;//TODO: replace with StampedLocks
private final SectionLoader loader; private final SectionLoader loader;
private final int lruSize; private final int lruSize;