Move some world gen queue limiting into the LodQuadTree

This commit is contained in:
James Seibel
2026-02-07 16:37:56 -06:00
parent 19412f80c5
commit d04e156dd1
5 changed files with 56 additions and 43 deletions
@@ -220,46 +220,28 @@ public class GeneratedFullDataSourceProvider extends FullDataSourceProviderV2 im
}
// we can't queue anything if the world generator isn't set up yet
IFullDataSourceRetrievalQueue worldGenQueue = this.worldGenQueueRef.get();
if (worldGenQueue == null)
{
// we can't queue anything if the world generator isn't set up yet
return false;
}
PriorityTaskPicker.Executor renderLoadExecutor = ThreadPoolUtil.getRenderLoadingExecutor();
if (renderLoadExecutor == null
|| renderLoadExecutor.getQueueSize() >= FullDataUpdatePropagatorV2.getMaxPropagateTaskCount() / 2)
{
// don't queue additional world gen requests if the render loader handler is overwhelmed,
// otherwise LODs may not load in properly
return false;
}
PriorityTaskPicker.Executor fileHandlerExecutor = ThreadPoolUtil.getFileHandlerExecutor();
if (fileHandlerExecutor == null
|| fileHandlerExecutor.getQueueSize() >= FullDataUpdatePropagatorV2.getMaxPropagateTaskCount() / 2)
{
// don't queue additional world gen requests if the file handler is overwhelmed,
// otherwise LODs may not load in properly
return false;
}
// TODO if the number of queued tasks last time was 0 we could increase this by 10?
int maxQueuedChunkCount = MAX_WORLD_GEN_REQUESTS_PER_THREAD * Config.Common.MultiThreading.numberOfThreads.get(); // for now we're just using the same logic as the world gen threads, it works well enough
if (SharedApi.INSTANCE.getQueuedChunkUpdateCount() >= maxQueuedChunkCount)
{
// don't queue additional world gen requests if there are
// a lot of chunks waiting to update
// (this is done to reduce thread starvation for chunk updates)
return false;
}
int maxWorldGenQueueCount = MAX_WORLD_GEN_REQUESTS_PER_THREAD * Config.Common.MultiThreading.numberOfThreads.get();
int currentQueueCount = SharedApi.INSTANCE.getQueuedChunkUpdateCount();
// don't queue additional world gen requests if there are
// a lot of chunks waiting to update
if (currentQueueCount >= maxWorldGenQueueCount)
{
return false;
}
if (this.delayedFullDataSourceSaveCache.getUnsavedCount() >= maxWorldGenQueueCount)
{
// don't queue additional world gen requests if there are
@@ -23,6 +23,7 @@ import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.listeners.IConfigListener;
import com.seibel.distanthorizons.core.enums.EDhDirection;
import com.seibel.distanthorizons.core.file.fullDatafile.V2.FullDataSourceProviderV2;
import com.seibel.distanthorizons.core.file.fullDatafile.V2.FullDataUpdatePropagatorV2;
import com.seibel.distanthorizons.core.generation.tasks.DataSourceRetrievalResult;
import com.seibel.distanthorizons.core.generation.tasks.ERetrievalResultState;
import com.seibel.distanthorizons.core.level.DhClientServerLevel;
@@ -41,6 +42,7 @@ import com.seibel.distanthorizons.core.util.ThreadUtil;
import com.seibel.distanthorizons.core.util.WorldGenUtil;
import com.seibel.distanthorizons.core.util.objects.quadTree.QuadNode;
import com.seibel.distanthorizons.core.util.objects.quadTree.QuadTree;
import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import com.seibel.distanthorizons.coreapi.util.MathUtil;
import it.unimi.dsi.fastutil.longs.LongArrayList;
@@ -414,7 +416,8 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
//region
// queue full data retrieval (world gen) requests if needed
if (this.fullDataSourceProvider.canQueueRetrievalNow()
if (threadPoolCanAcceptWorldGenTasks()
&& this.fullDataSourceProvider.canQueueRetrievalNow()
&& !this.queueThreadRunningRef.get())
{
this.queueThreadRunningRef.set(true); // don't run multiple threads at once
@@ -823,6 +826,33 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements IDebugRen
}
}
/**
* Prevents DH from
* accidentally starting to queue chunks out of order
* if the thread pool suddenly become (un)available while we're walking
* through the missing positions.
*/
private static boolean threadPoolCanAcceptWorldGenTasks()
{
// don't queue additional world gen requests if the render loader is busy
PriorityTaskPicker.Executor renderLoadExecutor = ThreadPoolUtil.getRenderLoadingExecutor();
if (renderLoadExecutor == null
|| renderLoadExecutor.getQueueSize() >= FullDataUpdatePropagatorV2.getMaxPropagateTaskCount() / 2)
{
return false;
}
// don't queue additional world gen requests if the file handler is busy
PriorityTaskPicker.Executor fileHandlerExecutor = ThreadPoolUtil.getFileHandlerExecutor();
if (fileHandlerExecutor == null
|| fileHandlerExecutor.getQueueSize() >= FullDataUpdatePropagatorV2.getMaxPropagateTaskCount() / 2)
{
return false;
}
return true;
}
//endregion world gen
@@ -9,8 +9,6 @@ import java.util.Optional;
public enum EDhInternalTextureFormat
{
// Default
/** TODO: This technically shouldn't be exposed to shaders since it's not in the specification, it's the default anyways */
RGBA(GL11C.GL_RGBA, EGlVersion.GL_11, EDhPixelFormat.RGBA),
// 8-bit normalized
@@ -121,9 +119,12 @@ public enum EDhInternalTextureFormat
}
}
public int getGlFormat() { return glFormat; }
public int getGlFormat() { return this.glFormat; }
public EDhPixelFormat getPixelFormat() { return this.expectedPixelFormat; }
public EGlVersion getMinimumGlVersion() { return this.minimumGlVersion; }
public EDhPixelFormat getPixelFormat() { return expectedPixelFormat; }
public EGlVersion getMinimumGlVersion() { return minimumGlVersion; }
}
@@ -51,10 +51,10 @@ public enum EDhPixelFormat
}
}
public int getGlFormat() { return glFormat; }
public int getGlFormat() { return this.glFormat; }
public EGlVersion getMinimumGlVersion() { return minimumGlVersion; }
public EGlVersion getMinimumGlVersion() { return this.minimumGlVersion; }
public boolean isInteger() { return isInteger; }
public boolean isInteger() { return this.isInteger; }
}
@@ -114,8 +114,8 @@ public class ThreadPoolUtil
fileHandlerThreadPool = taskPicker.createExecutor("IO");
renderSectionLoadThreadPool = taskPicker.createExecutor("Render Loader");
chunkToLodBuilderThreadPool = taskPicker.createExecutor("LOD Builder");
updatePropagatorThreadPool = taskPicker.createExecutor("Update Propagator", ThreadPoolUtil::onlyRunThreadIfCameraMovingSlowly);
worldGenThreadPool = taskPicker.createExecutor("World Gen", ThreadPoolUtil::onlyRunThreadIfCameraMovingSlowly);
updatePropagatorThreadPool = taskPicker.createExecutor("Update Propagator", ThreadPoolUtil::worldGenThreadsCanRun); // the update propagator isn't necessary when moving through the world, so we'll pause it along with the world generator when moving fast
worldGenThreadPool = taskPicker.createExecutor("World Gen", ThreadPoolUtil::worldGenThreadsCanRun);
@@ -168,7 +168,7 @@ public class ThreadPoolUtil
* @see LodUtil#ROCKET_ELYTRA_SPEED_IN_BLOCKS_PER_SEC
* @see LodUtil#MAX_SPECTATOR_SPEED_IN_BLOCKS_PER_SEC
*/
public static boolean onlyRunThreadIfCameraMovingSlowly()
public static boolean worldGenThreadsCanRun()
{
double cameraSpeed = ClientApi.INSTANCE.cameraSpeedRollingAverage.getAverage();
// stop these threads if moving a little bit slower than max elytra speed