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 //If we did put it in the queue, dont release the section
shouldFreeSection = false; shouldFreeSection = false;
} else { } 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 //Things went bad, set section to null and ensure section is freed
task.section = null; task.section = null;
shouldFreeSection = true; shouldFreeSection = true;

View File

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

View File

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

View File

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