improved lru cache and improved world import speed slightly

This commit is contained in:
mcrcortex
2025-01-30 06:55:39 +10:00
parent 772ec27ea1
commit 9e20eac7ab
4 changed files with 46 additions and 43 deletions

View File

@@ -138,7 +138,9 @@ public class RenderGenerationService {
//If we did put it in the queue, dont release the section
shouldFreeSection = false;
} else {
Logger.warn("Funkyness happened and multiple tasks for same section where in queue");
//This should no longer be a worry with LRU section cache
//Logger.info("Funkyness happened and multiple tasks for same section where in queue");
//Things went bad, set section to null and ensure section is freed
task.section = null;
shouldFreeSection = true;

View File

@@ -1,5 +1,6 @@
package me.cortex.voxy.common.thread;
import me.cortex.voxy.common.Logger;
import me.cortex.voxy.common.util.Pair;
import me.cortex.voxy.common.util.TrackedObject;
import net.minecraft.client.MinecraftClient;
@@ -76,8 +77,7 @@ public class ServiceSlice extends TrackedObject {
try {
ctx.run();
} catch (Exception e) {
System.err.println("Unexpected error occurred while executing a service job, expect things to break badly");
e.printStackTrace();
Logger.error("Unexpected error occurred while executing a service job, expect things to break badly", e);
MinecraftClient.getInstance().execute(()->MinecraftClient.getInstance().player.sendMessage(Text.literal("A voxy service had an exception while executing please check logs and report error"), true));
} finally {
if (this.activeCount.decrementAndGet() < 0) {

View File

@@ -1,6 +1,7 @@
package me.cortex.voxy.common.voxelization;
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
import me.cortex.voxy.common.util.Pair;
import me.cortex.voxy.common.world.other.Mipper;
import me.cortex.voxy.common.world.other.Mapper;
import net.minecraft.block.BlockState;
@@ -11,30 +12,34 @@ import net.minecraft.world.chunk.ReadableContainer;
public class WorldConversionFactory {
//TODO: create a mapping for world/mapper -> local mapping
private static final ThreadLocal<Reference2IntOpenHashMap<BlockState>> BLOCK_CACHE = ThreadLocal.withInitial(Reference2IntOpenHashMap::new);
private static final ThreadLocal<Pair<int[],Reference2IntOpenHashMap<BlockState>>> THREAD_LOCAL = ThreadLocal.withInitial(()->new Pair<>(new int[4*4*4], new Reference2IntOpenHashMap<>()));
public static VoxelizedSection convert(VoxelizedSection section,
Mapper stateMapper,
PalettedContainer<BlockState> blockContainer,
ReadableContainer<RegistryEntry<Biome>> biomeContainer,
ILightingSupplier lightSupplier) {
var blockCache = BLOCK_CACHE.get();
var threadLocal = THREAD_LOCAL.get();
var blockCache = threadLocal.right();
var biomes = threadLocal.left();
var data = section.section;
int blockId = -1;
BlockState block = null;
{
int i = 0;
for (int y = 0; y < 4; y++) {
for (int z = 0; z < 4; z++) {
for (int x = 0; x < 4; x++) {
biomes[i++] = stateMapper.getIdForBiome(biomeContainer.get(x, y, z));
}
}
}
}
for (int oy = 0; oy < 4; oy++) {
for (int oz = 0; oz < 4; oz++) {
for (int ox = 0; ox < 4; ox++) {
int biomeId = stateMapper.getIdForBiome(biomeContainer.get(ox, oy, oz));
for (int iy = 0; iy < 4; iy++) {
for (int iz = 0; iz < 4; iz++) {
for (int ix = 0; ix < 4; ix++) {
int x = (ox<<2)|ix;
int y = (oy<<2)|iy;
int z = (oz<<2)|iz;
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
var state = blockContainer.get(x, y, z);
byte light = lightSupplier.supply(x,y,z,state);
if (!(state.isAir() && (light==0))) {
@@ -51,16 +56,13 @@ public class WorldConversionFactory {
block = state;
}
}
data[G(x, y, z)] = Mapper.composeMappingId(light, blockId, biomeId);
data[G(x, y, z)] = Mapper.composeMappingId(light, blockId, biomes[((y&0b1100)<<2)|(z&0b1100)|(x>>2)]);
} else {
data[G(x, y, z)] = Mapper.AIR;
}
}
}
}
}
}
}
return section;
}

View File

@@ -41,7 +41,7 @@ public class ActiveSectionTracker {
var cache = this.loadedSectionCache[index];
VolatileHolder<WorldSection> holder = null;
boolean isLoader = false;
WorldSection cachedSection = null;
WorldSection section;
synchronized (cache) {
holder = cache.get(key);
if (holder == null) {
@@ -49,23 +49,19 @@ public class ActiveSectionTracker {
cache.put(key, holder);
isLoader = true;
}
var section = holder.obj;
section = holder.obj;
if (section != null) {
section.acquire();
return section;
}
if (isLoader) {
cachedSection = this.lruSecondaryCache[index].remove(key);
if (cachedSection != null) {
cachedSection.primeForReuse();
}
section = this.lruSecondaryCache[index].remove(key);
}
}
//If this thread was the one to create the reference then its the thread to load the section
if (isLoader) {
int status = 0;
var section = cachedSection;
if (section == null) {//Secondary cache miss
section = new WorldSection(WorldEngine.getLevel(key),
WorldEngine.getX(key),
@@ -87,7 +83,10 @@ public class ActiveSectionTracker {
//We need to set the data to air as it is undefined state
Arrays.fill(section.data, 0);
}
} else {
section.primeForReuse();
}
section.acquire();
holder.obj = section;
if (nullOnEmpty && status == 1) {//If its air return null as stated, release the section aswell
@@ -96,7 +95,6 @@ public class ActiveSectionTracker {
}
return section;
} else {
WorldSection section = null;
while ((section = holder.obj) == null)
Thread.onSpinWait();
@@ -117,6 +115,7 @@ public class ActiveSectionTracker {
if (cache.remove(section.key).obj != section) {
throw new IllegalStateException("Removed section not the same as the referenced section in the cache");
}
//Add section to secondary cache while primary is locked
var lruCache = this.lruSecondaryCache[index];
var prev = lruCache.put(section.key, section);