Added render cache
This commit is contained in:
@@ -34,17 +34,23 @@ public class DistanceTracker {
|
|||||||
// there will still be 32 chunks untill the first lod drop
|
// there will still be 32 chunks untill the first lod drop
|
||||||
// if the game is set to 16, then there will be 48 chunks until the drop
|
// if the game is set to 16, then there will be 48 chunks until the drop
|
||||||
for (int i = 0; i < this.loDRings.length; i++) {
|
for (int i = 0; i < this.loDRings.length; i++) {
|
||||||
|
//TODO: FIXME: check that the level shift is right when inc/dec
|
||||||
int capRing = i;
|
int capRing = i;
|
||||||
this.loDRings[i] = new TransitionRing2D(6+i, lodRingScales[i], (x, z) -> this.dec(capRing+1, x, z), (x, z) -> this.inc(capRing+1, x, z));
|
this.loDRings[i] = new TransitionRing2D(6+i, lodRingScales[i], (x, z) -> this.dec(capRing+1, x, z), (x, z) -> this.inc(capRing+1, x, z));
|
||||||
|
|
||||||
//TODO:FIXME i think the radius is wrong and (lodRingScales[i]) needs to be (lodRingScales[i]<<1) since the transition ring (the thing above)
|
//TODO:FIXME i think the radius is wrong and (lodRingScales[i]) needs to be (lodRingScales[i]<<1) since the transition ring (the thing above)
|
||||||
// acts on LoD level + 1
|
// acts on LoD level + 1
|
||||||
this.cacheLoadRings[i] = new TransitionRing2D(5+i, lodRingScales[i] + cacheLoadDistance, (x, z) -> {
|
this.cacheLoadRings[i] = new TransitionRing2D(5+i, (lodRingScales[i]<<1) + cacheLoadDistance, (x, z) -> {
|
||||||
//When entering a cache ring, trigger a mesh op and inject into cache
|
//When entering a cache ring, trigger a mesh op and inject into cache
|
||||||
|
for (int y = this.minYSection>>capRing; y <= this.maxYSection>>capRing; y++) {
|
||||||
|
this.tracker.addCache(capRing, x, y, z);
|
||||||
|
}
|
||||||
}, (x, z) -> {});
|
}, (x, z) -> {});
|
||||||
this.cacheUnloadRings[i] = new TransitionRing2D(5+i, lodRingScales[i] + cacheUnloadDistance, (x, z) -> {}, (x, z) -> {
|
this.cacheUnloadRings[i] = new TransitionRing2D(5+i, (lodRingScales[i]<<1) + cacheUnloadDistance, (x, z) -> {}, (x, z) -> {
|
||||||
//When exiting the cache unload ring, tell the cache to dump whatever mesh it has cached and not add any mesh from that position
|
//When exiting the cache unload ring, tell the cache to dump whatever mesh it has cached and not add any mesh from that position
|
||||||
|
for (int y = this.minYSection>>capRing; y <= this.maxYSection>>capRing; y++) {
|
||||||
|
this.tracker.removeCache(capRing, x, y, z);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,8 @@ public class VoxelCore {
|
|||||||
|
|
||||||
//To get to chunk scale multiply the scale by 2, the scale is after how many chunks does the lods halve
|
//To get to chunk scale multiply the scale by 2, the scale is after how many chunks does the lods halve
|
||||||
int q = VoxyConfig.CONFIG.qualityScale;
|
int q = VoxyConfig.CONFIG.qualityScale;
|
||||||
this.distanceTracker = new DistanceTracker(this.renderTracker, new int[]{q,q,q,q}, 2, 4);
|
//TODO: add an option for cache load and unload distance
|
||||||
|
this.distanceTracker = new DistanceTracker(this.renderTracker, new int[]{q,q,q,q}, 8, 16);
|
||||||
System.out.println("Distance tracker initialized");
|
System.out.println("Distance tracker initialized");
|
||||||
|
|
||||||
this.postProcessing = new PostProcessing();
|
this.postProcessing = new PostProcessing();
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
|
|
||||||
//Tracks active sections, dispatches updates to the build system, everything related to rendering flows through here
|
//Tracks active sections, dispatches updates to the build system, everything related to rendering flows through here
|
||||||
public class RenderTracker {
|
public class RenderTracker {
|
||||||
private static final class ActiveSectionObject {
|
|
||||||
private int buildFlags;
|
|
||||||
}
|
|
||||||
private final WorldEngine world;
|
private final WorldEngine world;
|
||||||
private RenderGenerationService renderGen;
|
private RenderGenerationService renderGen;
|
||||||
private final AbstractFarWorldRenderer renderer;
|
private final AbstractFarWorldRenderer renderer;
|
||||||
@@ -109,8 +106,14 @@ public class RenderTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Enqueues a renderTask for a section to cache the result
|
//Enqueues a renderTask for a section to cache the result
|
||||||
public void addCache() {
|
public void addCache(int lvl, int x, int y, int z) {
|
||||||
|
this.renderGen.markCache(lvl, x, y, z);
|
||||||
|
this.renderGen.enqueueTask(lvl, x, y, z, ((lvl1, x1, y1, z1) -> true));//TODO: replace the true identity lambda with a callback check to the render cache
|
||||||
|
}
|
||||||
|
|
||||||
|
//Removes the position from the cache
|
||||||
|
public void removeCache(int lvl, int x, int y, int z) {
|
||||||
|
this.renderGen.unmarkCache(lvl, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -127,6 +130,11 @@ public class RenderTracker {
|
|||||||
this.renderGen.enqueueTask(section.lvl, section.x+1, section.y, section.z, this::shouldStillBuild);
|
this.renderGen.enqueueTask(section.lvl, section.x+1, section.y, section.z, this::shouldStillBuild);
|
||||||
this.renderGen.enqueueTask(section.lvl, section.x, section.y, section.z-1, this::shouldStillBuild);
|
this.renderGen.enqueueTask(section.lvl, section.x, section.y, section.z-1, this::shouldStillBuild);
|
||||||
this.renderGen.enqueueTask(section.lvl, section.x, section.y, section.z+1, this::shouldStillBuild);
|
this.renderGen.enqueueTask(section.lvl, section.x, section.y, section.z+1, this::shouldStillBuild);
|
||||||
|
this.renderGen.clearCache(section.lvl, section.x, section.y, section.z);
|
||||||
|
this.renderGen.clearCache(section.lvl, section.x-1, section.y, section.z);
|
||||||
|
this.renderGen.clearCache(section.lvl, section.x+1, section.y, section.z);
|
||||||
|
this.renderGen.clearCache(section.lvl, section.x, section.y, section.z-1);
|
||||||
|
this.renderGen.clearCache(section.lvl, section.x, section.y, section.z+1);
|
||||||
}
|
}
|
||||||
//this.renderGen.enqueueTask(section);
|
//this.renderGen.enqueueTask(section);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,22 +6,56 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
// when a section is unloaded from the gpu, put it into a download stream and recover the BuiltSection
|
// when a section is unloaded from the gpu, put it into a download stream and recover the BuiltSection
|
||||||
// and put that into the cache, then remove the uploaded mesh from the cache
|
// and put that into the cache, then remove the uploaded mesh from the cache
|
||||||
public class BuiltSectionMeshCache {
|
public class BuiltSectionMeshCache {
|
||||||
|
private static final BuiltSection HOLDER = new BuiltSection(-1);
|
||||||
private final ConcurrentHashMap<Long, BuiltSection> renderCache = new ConcurrentHashMap<>(1000,0.75f,10);
|
private final ConcurrentHashMap<Long, BuiltSection> renderCache = new ConcurrentHashMap<>(1000,0.75f,10);
|
||||||
|
|
||||||
public BuiltSection getMesh(long key) {
|
public BuiltSection getMesh(long key) {
|
||||||
return null;
|
BuiltSection[] res = new BuiltSection[1];
|
||||||
|
this.renderCache.computeIfPresent(key, (a, value) -> {
|
||||||
|
if (value == null || value == HOLDER) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
res[0] = value.clone();
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
return res[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
//Returns true if the mesh was used, (this is so the parent method can free mesh object)
|
//Returns true if the mesh was used, (this is so the parent method can free mesh object)
|
||||||
public boolean putMesh(BuiltSection mesh) {
|
public boolean putMesh(BuiltSection mesh) {
|
||||||
return false;
|
var mesh2 = this.renderCache.computeIfPresent(mesh.position, (id, value) -> {
|
||||||
|
value.free();
|
||||||
|
return mesh;
|
||||||
|
});
|
||||||
|
return mesh2 == mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearMesh(long key) {
|
public void clearMesh(long key) {
|
||||||
|
this.renderCache.computeIfPresent(key, (a,val)->{
|
||||||
|
if (val != HOLDER) {
|
||||||
|
val.free();
|
||||||
|
}
|
||||||
|
return HOLDER;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markCache(long key) {
|
||||||
|
this.renderCache.putIfAbsent(key, HOLDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unmarkCache(long key) {
|
||||||
|
var mesh = this.renderCache.remove(key);
|
||||||
|
if (mesh != null && mesh != HOLDER) {
|
||||||
|
mesh.free();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void free() {
|
public void free() {
|
||||||
|
for (var mesh : this.renderCache.values()) {
|
||||||
|
if (mesh != HOLDER) {
|
||||||
|
mesh.free();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ public class RenderGenerationService {
|
|||||||
{
|
{
|
||||||
var cache = this.meshCache.getMesh(ikey);
|
var cache = this.meshCache.getMesh(ikey);
|
||||||
if (cache != null) {
|
if (cache != null) {
|
||||||
this.resultConsumer.accept(cache.clone());
|
this.resultConsumer.accept(cache);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,6 +109,21 @@ public class RenderGenerationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Tells the render cache that the mesh at the specified position should be cached
|
||||||
|
public void markCache(int lvl, int x, int y, int z) {
|
||||||
|
this.meshCache.markCache(WorldEngine.getWorldSectionId(lvl, x, y, z));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Tells the render cache that the mesh at the specified position should not be cached/any previous cache result, freed
|
||||||
|
public void unmarkCache(int lvl, int x, int y, int z) {
|
||||||
|
this.meshCache.unmarkCache(WorldEngine.getWorldSectionId(lvl, x, y, z));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Resets a chunks cache mesh
|
||||||
|
public void clearCache(int lvl, int x, int y, int z) {
|
||||||
|
this.meshCache.clearMesh(WorldEngine.getWorldSectionId(lvl, x, y, z));
|
||||||
|
}
|
||||||
|
|
||||||
public void removeTask(int lvl, int x, int y, int z) {
|
public void removeTask(int lvl, int x, int y, int z) {
|
||||||
synchronized (this.taskQueue) {
|
synchronized (this.taskQueue) {
|
||||||
if (this.taskQueue.remove(WorldEngine.getWorldSectionId(lvl, x, y, z)) != null) {
|
if (this.taskQueue.remove(WorldEngine.getWorldSectionId(lvl, x, y, z)) != null) {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class WorldEngine {
|
|||||||
this.storage = storageBackend;
|
this.storage = storageBackend;
|
||||||
this.mapper = new Mapper(this.storage);
|
this.mapper = new Mapper(this.storage);
|
||||||
//4 cache size bits means that the section tracker has 16 separate maps that it uses
|
//4 cache size bits means that the section tracker has 16 separate maps that it uses
|
||||||
this.sectionTracker = new ActiveSectionTracker(4, this::unsafeLoadSection);
|
this.sectionTracker = new ActiveSectionTracker(3, this::unsafeLoadSection);
|
||||||
|
|
||||||
this.savingService = new SectionSavingService(this, savingServiceWorkers, compressionLevel);
|
this.savingService = new SectionSavingService(this, savingServiceWorkers, compressionLevel);
|
||||||
this.ingestService = new VoxelIngestService(this, ingestWorkers);
|
this.ingestService = new VoxelIngestService(this, ingestWorkers);
|
||||||
|
|||||||
Reference in New Issue
Block a user