Fixed multiple major RAM issues. Next one is the 100/s reload issue...

This commit is contained in:
TomTheFurry
2022-08-08 23:00:30 +08:00
parent 6c8a7ef989
commit 6a49a100e7
7 changed files with 46 additions and 20 deletions
@@ -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<RenderBuffer> 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;
@@ -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<ColumnRenderBuffer> 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;
@@ -74,7 +74,7 @@ public class LodRenderSection {
}
public boolean canRender() {
return isLoaded() && lodRenderSource.isRenderReady();
return isLoaded() && isRenderEnabled && lodRenderSource.isRenderReady();
}
public boolean isLoaded() {
@@ -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();
@@ -145,7 +145,7 @@ public class LocalDataFileHandler implements IDataSourceProvider {
*/
@Override
public CompletableFuture<Void> flushAndSave() {
ArrayList<CompletableFuture<Void>> futures = new ArrayList<CompletableFuture<Void>>();
ArrayList<CompletableFuture<Void>> 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
}
}
@@ -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;
}
@@ -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);