diff --git a/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderSource.java b/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderSource.java index 12a294b10..f7fdb1165 100644 --- a/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderSource.java +++ b/src/main/java/com/seibel/lod/core/a7/datatype/column/ColumnRenderSource.java @@ -11,11 +11,13 @@ import com.seibel.lod.core.a7.pos.DhSectionPos; import com.seibel.lod.core.a7.render.RenderBuffer; import com.seibel.lod.core.a7.save.io.render.RenderMetaFile; import com.seibel.lod.core.enums.ELodDirection; +import com.seibel.lod.core.logging.DhLoggerBuilder; import com.seibel.lod.core.objects.LodDataView; import com.seibel.lod.core.a7.level.ILevel; import com.seibel.lod.core.a7.render.LodQuadTree; import com.seibel.lod.core.a7.render.LodRenderSection; import com.seibel.lod.core.a7.datatype.LodRenderSource; +import org.apache.logging.log4j.Logger; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -27,6 +29,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; public class ColumnRenderSource implements LodRenderSource, IColumnDatatype { + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); public static final boolean DO_SAFETY_CHECKS = true; public static final byte SECTION_SIZE_OFFSET = 6; public static final int SECTION_SIZE = 1 << SECTION_SIZE_OFFSET; @@ -253,7 +256,7 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype { private void tryBuildBuffer(IClientLevel level, LodQuadTree quadTree) { - if (inBuildRenderBuffer == null) { + if (inBuildRenderBuffer == null && !ColumnRenderBuffer.isBusy()) { ColumnRenderSource[] data = new ColumnRenderSource[ELodDirection.ADJ_DIRECTIONS.length]; for (ELodDirection direction : ELodDirection.ADJ_DIRECTIONS) { LodRenderSection section = quadTree.getSection(sectionPos.getAdjacent(direction)); //FIXME: Handle traveling through different detail levels @@ -266,6 +269,7 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype { } private void cancelBuildBuffer() { if (inBuildRenderBuffer != null) { + LOGGER.info("Cancelling build of render buffer for {}", sectionPos); inBuildRenderBuffer.cancel(true); inBuildRenderBuffer = null; } @@ -275,7 +279,7 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype { @Override public void enableRender(IClientLevel level, LodQuadTree quadTree) { this.level = level; - tryBuildBuffer(level, quadTree); + //tryBuildBuffer(level, quadTree); } @Override @@ -285,7 +289,7 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype { @Override public boolean isRenderReady() { - return (inBuildRenderBuffer != null && inBuildRenderBuffer.isDone()); + return inBuildRenderBuffer == null || inBuildRenderBuffer.isDone(); } @Override @@ -293,15 +297,23 @@ public class ColumnRenderSource implements LodRenderSource, IColumnDatatype { cancelBuildBuffer(); } + //FIXME: Temp Hack + private long lastNs = -1; + private static final long SWAP_TIMEOUT = /* 10 sec */ 10_000_000_000L; @Override public boolean trySwapRenderBuffer(LodQuadTree quadTree, AtomicReference referenceSlot) { + if (lastNs != -1 && System.nanoTime() - lastNs < SWAP_TIMEOUT) { + return false; + } if (inBuildRenderBuffer != null && inBuildRenderBuffer.isDone()) { + lastNs = System.nanoTime(); + LOGGER.info("Swapping render buffer for {}", sectionPos); RenderBuffer oldBuffer = referenceSlot.getAndSet(inBuildRenderBuffer.join()); if (oldBuffer instanceof ColumnRenderBuffer) usedBuffer = (ColumnRenderBuffer) oldBuffer; inBuildRenderBuffer = null; return true; - } else { + } else if (inBuildRenderBuffer == null && !ColumnRenderBuffer.isBusy()) { tryBuildBuffer(level, quadTree); } return false; diff --git a/src/main/java/com/seibel/lod/core/a7/datatype/column/render/ColumnRenderBuffer.java b/src/main/java/com/seibel/lod/core/a7/datatype/column/render/ColumnRenderBuffer.java index 46a39b5e6..a95ee2a68 100644 --- a/src/main/java/com/seibel/lod/core/a7/datatype/column/render/ColumnRenderBuffer.java +++ b/src/main/java/com/seibel/lod/core/a7/datatype/column/render/ColumnRenderBuffer.java @@ -28,10 +28,8 @@ import org.lwjgl.opengl.GL32; import java.lang.invoke.MethodHandles; import java.nio.ByteBuffer; import java.util.Iterator; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; import static com.seibel.lod.core.render.GLProxy.GL_LOGGER; @@ -40,6 +38,7 @@ public class ColumnRenderBuffer extends RenderBuffer { //TODO: Make the pool use configurable number of threads public static final ExecutorService BUFFER_BUILDERS = LodUtil.makeThreadPool(4, "BufferBuilder"); public static final ExecutorService BUFFER_UPLOADER = LodUtil.makeSingleThreadPool("ColumnBufferUploader"); + public static final int MAX_CONCURRENT_CALL = 8; public static final ConfigBasedLogger EVENT_LOGGER = new ConfigBasedLogger(LogManager.getLogger(), () -> Config.Client.Advanced.Debugging.DebugSwitch.logRendererBufferEvent.get()); @@ -180,9 +179,19 @@ public class ColumnRenderBuffer extends RenderBuffer { }); } + private static long getCurrentJobsCount() { + long jobs = ((ThreadPoolExecutor) BUFFER_BUILDERS).getQueue().stream().filter(t -> !((Future) t).isDone()).count(); + jobs += ((ThreadPoolExecutor) BUFFER_UPLOADER).getQueue().stream().filter(t -> !((Future) t).isDone()).count(); + return jobs; + } + + public static boolean isBusy() { + return getCurrentJobsCount() > MAX_CONCURRENT_CALL; + } public static CompletableFuture build(IClientLevel clientLevel, ColumnRenderBuffer usedBuffer, ColumnRenderSource data, ColumnRenderSource[] adjData) { - EVENT_LOGGER.trace("RenderRegion startBuild @ {}", data.sectionPos); + if (isBusy()) return null; + LOGGER.info("RenderRegion startBuild @ {}", data.sectionPos); return CompletableFuture.supplyAsync(() -> { try { EVENT_LOGGER.trace("RenderRegion start QuadBuild @ {}", data.sectionPos); @@ -201,7 +210,7 @@ public class ColumnRenderBuffer extends RenderBuffer { throw e; } catch (Throwable e3) { - EVENT_LOGGER.error("\"LodNodeBufferBuilder\" was unable to build quads: ", e3); + LOGGER.error("\"LodNodeBufferBuilder\" was unable to build quads: ", e3); throw e3; } }, BUFFER_BUILDERS) @@ -229,10 +238,11 @@ public class ColumnRenderBuffer extends RenderBuffer { } catch (InterruptedException e) { throw UncheckedInterruptedException.convert(e); } catch (Throwable e3) { - EVENT_LOGGER.error("\"LodNodeBufferBuilder\" was unable to upload buffer: ", e3); + LOGGER.error("\"LodNodeBufferBuilder\" was unable to upload buffer: ", e3); throw e3; } }, BUFFER_UPLOADER).handle((v, e) -> { + LOGGER.info("RenderRegion endBuild @ {}", data.sectionPos); if (e != null) { usedBuffer.close(); return null; diff --git a/src/main/java/com/seibel/lod/core/a7/render/LodRenderSection.java b/src/main/java/com/seibel/lod/core/a7/render/LodRenderSection.java index a15fccb02..ee43ebcf8 100644 --- a/src/main/java/com/seibel/lod/core/a7/render/LodRenderSection.java +++ b/src/main/java/com/seibel/lod/core/a7/render/LodRenderSection.java @@ -74,7 +74,7 @@ public class LodRenderSection { } public boolean canRender() { - return isLoaded() && lodRenderSource.isRenderReady(); + return isLoaded() && isRenderEnabled && lodRenderSource.isRenderReady(); } public boolean isLoaded() { diff --git a/src/main/java/com/seibel/lod/core/a7/save/io/file/DataMetaFile.java b/src/main/java/com/seibel/lod/core/a7/save/io/file/DataMetaFile.java index 6bf298eb4..a03a2e937 100644 --- a/src/main/java/com/seibel/lod/core/a7/save/io/file/DataMetaFile.java +++ b/src/main/java/com/seibel/lod/core/a7/save/io/file/DataMetaFile.java @@ -193,10 +193,12 @@ public class DataMetaFile extends MetaFile { if (e != null) { LOGGER.error("Uncaught error loading file {}: ", path, e); future.complete(null); + data.set(null); + } else { + future.complete(f); + new DataObjTracker(f); + data.set(new SoftReference<>(f)); } - future.complete(f); - new DataObjTracker(f); - data.set(new SoftReference<>(f)); }); return future; } @@ -215,6 +217,7 @@ public class DataMetaFile extends MetaFile { for (ChunkSizedData chunk : _backQueue.queue) { data.update(chunk); } + _backQueue.queue.clear(); write(data); LOGGER.info("Updated Data file at {} for sect {} with {} chunk writes.", path, pos, count); } else localVer = localVersion.get(); diff --git a/src/main/java/com/seibel/lod/core/a7/save/io/file/LocalDataFileHandler.java b/src/main/java/com/seibel/lod/core/a7/save/io/file/LocalDataFileHandler.java index c93de07f1..cff9bc97e 100644 --- a/src/main/java/com/seibel/lod/core/a7/save/io/file/LocalDataFileHandler.java +++ b/src/main/java/com/seibel/lod/core/a7/save/io/file/LocalDataFileHandler.java @@ -145,7 +145,7 @@ public class LocalDataFileHandler implements IDataSourceProvider { */ @Override public CompletableFuture flushAndSave() { - ArrayList> futures = new ArrayList>(); + ArrayList> futures = new ArrayList<>(); for (DataMetaFile metaFile : files.values()) { futures.add(metaFile.flushAndSave(fileReaderThread)); } @@ -167,7 +167,6 @@ public class LocalDataFileHandler implements IDataSourceProvider { @Override public void close() { DataMetaFile.debugCheck(); - //TODO } } diff --git a/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderMetaFile.java b/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderMetaFile.java index cc6f805e5..bdaa74cad 100644 --- a/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderMetaFile.java +++ b/src/main/java/com/seibel/lod/core/a7/save/io/render/RenderMetaFile.java @@ -134,9 +134,11 @@ public class RenderMetaFile extends MetaFile { if (e != null) { LOGGER.error("Uncaught error loading file {}: ", path, e); future.complete(null); + data.set(null); + } else { + future.complete(renderSource); + data.set(new SoftReference<>(renderSource)); } - future.complete(renderSource); - data.set(new SoftReference<>(renderSource)); }); return future; } diff --git a/src/main/java/com/seibel/lod/core/util/LodUtil.java b/src/main/java/com/seibel/lod/core/util/LodUtil.java index 49d1e4af6..74eaf90f3 100644 --- a/src/main/java/com/seibel/lod/core/util/LodUtil.java +++ b/src/main/java/com/seibel/lod/core/util/LodUtil.java @@ -433,7 +433,7 @@ public class LodUtil throw new AssertFailureException("Assert Not Reach failed:\n " + formatLog(message, args)); } public static ExecutorService makeSingleThreadPool(String name, int relativePriority) { - return Executors.newSingleThreadExecutor(new LodThreadFactory(name, Thread.NORM_PRIORITY+relativePriority)); + return Executors.newFixedThreadPool(1, new LodThreadFactory(name, Thread.NORM_PRIORITY+relativePriority)); } public static ExecutorService makeSingleThreadPool(Class clazz, int relativePriority) { return makeSingleThreadPool(clazz.getSimpleName(), relativePriority);