diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataSourceProvider.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataSourceProvider.java index 7de3aac67..4fdf7effc 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataSourceProvider.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataSourceProvider.java @@ -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 diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/QuadTree/LodQuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/render/QuadTree/LodQuadTree.java index a8a709cba..6ed952b83 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/QuadTree/LodQuadTree.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/QuadTree/LodQuadTree.java @@ -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 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 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 diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/EDhInternalTextureFormat.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/EDhInternalTextureFormat.java index a053b0a14..b307aafa6 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/EDhInternalTextureFormat.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/EDhInternalTextureFormat.java @@ -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; } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/EDhPixelFormat.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/EDhPixelFormat.java index d3b77f3d9..a9bac119f 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/EDhPixelFormat.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/EDhPixelFormat.java @@ -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; } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/threading/ThreadPoolUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/threading/ThreadPoolUtil.java index 67c8440ed..17375e541 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/threading/ThreadPoolUtil.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/threading/ThreadPoolUtil.java @@ -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