Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core
This commit is contained in:
-4
@@ -19,10 +19,6 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.config.eventHandlers;
|
||||
|
||||
import com.seibel.distanthorizons.api.DhApi;
|
||||
import com.seibel.distanthorizons.api.enums.config.ELodShading;
|
||||
import com.seibel.distanthorizons.api.enums.config.EMaxHorizontalResolution;
|
||||
import com.seibel.distanthorizons.api.enums.config.EVerticalQuality;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.listeners.IConfigListener;
|
||||
|
||||
|
||||
-48
@@ -467,52 +467,4 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu
|
||||
@Override
|
||||
public int getWidthInDataPoints() { return this.width; }
|
||||
|
||||
|
||||
|
||||
//========//
|
||||
// unused //
|
||||
//========//
|
||||
|
||||
public void updateFromLowerCompleteSource(CompleteFullDataSource subData)
|
||||
{
|
||||
LodUtil.assertTrue(this.sectionPos.overlapsExactly(subData.sectionPos));
|
||||
LodUtil.assertTrue(subData.sectionPos.getDetailLevel() < this.sectionPos.getDetailLevel());
|
||||
if (!firstDataPosCanAffectSecond(this.sectionPos, subData.sectionPos))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DhSectionPos lowerSectPos = subData.sectionPos;
|
||||
byte detailDiff = (byte) (this.sectionPos.getDetailLevel() - subData.sectionPos.getDetailLevel());
|
||||
byte targetDataDetail = this.getDataDetailLevel();
|
||||
DhLodPos minDataPos = this.sectionPos.getMinCornerLodPos(targetDataDetail);
|
||||
if (detailDiff <= SECTION_SIZE_OFFSET)
|
||||
{
|
||||
int count = 1 << detailDiff;
|
||||
int dataPerCount = WIDTH / count;
|
||||
DhLodPos subDataPos = lowerSectPos.getSectionBBoxPos().getCornerLodPos(targetDataDetail);
|
||||
int dataOffsetX = subDataPos.x - minDataPos.x;
|
||||
int dataOffsetZ = subDataPos.z - minDataPos.z;
|
||||
LodUtil.assertTrue(dataOffsetX >= 0 && dataOffsetX < WIDTH && dataOffsetZ >= 0 && dataOffsetZ < WIDTH);
|
||||
|
||||
for (int xOffset = 0; xOffset < count; xOffset++)
|
||||
{
|
||||
for (int zOffset = 0; zOffset < count; zOffset++)
|
||||
{
|
||||
SingleColumnFullDataAccessor column = this.get(xOffset + dataOffsetX, zOffset + dataOffsetZ);
|
||||
column.downsampleFrom(subData.subView(dataPerCount, xOffset * dataPerCount, zOffset * dataPerCount));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Count == 1
|
||||
DhLodPos subDataPos = lowerSectPos.getSectionBBoxPos().convertToDetailLevel(targetDataDetail);
|
||||
int dataOffsetX = subDataPos.x - minDataPos.x;
|
||||
int dataOffsetZ = subDataPos.z - minDataPos.z;
|
||||
LodUtil.assertTrue(dataOffsetX >= 0 && dataOffsetX < WIDTH && dataOffsetZ >= 0 && dataOffsetZ < WIDTH);
|
||||
subData.get(0, 0).deepCopyTo(get(dataOffsetX, dataOffsetZ));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -382,7 +382,7 @@ public class ColumnRenderBuffer extends AbstractRenderBuffer
|
||||
{
|
||||
this.buffersUploaded = false;
|
||||
|
||||
GLProxy.getInstance().recordOpenGlCall(() ->
|
||||
GLProxy.getInstance().queueRunningOnRenderThread(() ->
|
||||
{
|
||||
for (GLVertexBuffer buffer : this.vbos)
|
||||
{
|
||||
|
||||
+38
-28
@@ -62,8 +62,8 @@ public abstract class AbstractDataSourceHandler<TDataSource extends IDataSource<
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public AbstractDataSourceHandler(TDhLevel level, AbstractSaveStructure saveStructure, AbstractDataSourceRepo repo) { this(level, saveStructure, repo, null); }
|
||||
public AbstractDataSourceHandler(TDhLevel level, AbstractSaveStructure saveStructure, AbstractDataSourceRepo repo, @Nullable File saveDirOverride)
|
||||
public AbstractDataSourceHandler(TDhLevel level, AbstractSaveStructure saveStructure) { this(level, saveStructure, null); }
|
||||
public AbstractDataSourceHandler(TDhLevel level, AbstractSaveStructure saveStructure, @Nullable File saveDirOverride)
|
||||
{
|
||||
this.level = level;
|
||||
this.saveDir = (saveDirOverride == null) ? saveStructure.getFullDataFolder(level.getLevelWrapper()) : saveDirOverride;
|
||||
@@ -83,7 +83,7 @@ public abstract class AbstractDataSourceHandler<TDataSource extends IDataSource<
|
||||
this.queueSaveLockArray[i] = new ReentrantLock();
|
||||
}
|
||||
|
||||
this.repo = repo;
|
||||
this.repo = this.createRepo();
|
||||
|
||||
// determine the top detail level currently in the database
|
||||
int maxSectionDetailLevel = this.repo.getMaxSectionDetailLevel();
|
||||
@@ -97,6 +97,9 @@ public abstract class AbstractDataSourceHandler<TDataSource extends IDataSource<
|
||||
// abstract methods //
|
||||
//==================//
|
||||
|
||||
/** When this is called the parent folders should be created */
|
||||
protected abstract AbstractDataSourceRepo createRepo();
|
||||
|
||||
protected abstract TDataSource createDataSourceFromDto(DataSourceDto dto) throws InterruptedException, IOException;
|
||||
/**
|
||||
* Creates a new data source using any DTOs already present in the database.
|
||||
@@ -182,20 +185,31 @@ public abstract class AbstractDataSourceHandler<TDataSource extends IDataSource<
|
||||
//===============//
|
||||
|
||||
@Override
|
||||
public void updateDataSourcesWithChunkData(ChunkSizedFullDataAccessor chunkDataView)
|
||||
{
|
||||
DhSectionPos chunkSectionPos = chunkDataView.getSectionPos().convertNewToDetailLevel(DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL);
|
||||
this.recursivelyUpdateDataSourcesAsync(chunkSectionPos, chunkDataView);
|
||||
}
|
||||
/** Updates every data source from this position up to {@link AbstractDataSourceHandler#topSectionDetailLevelRef} */
|
||||
protected void recursivelyUpdateDataSourcesAsync(DhSectionPos pos, ChunkSizedFullDataAccessor chunkDataView)
|
||||
public CompletableFuture<Void> updateDataSourcesWithChunkDataAsync(ChunkSizedFullDataAccessor chunkDataView)
|
||||
{
|
||||
DhSectionPos pos = chunkDataView.getSectionPos().convertNewToDetailLevel(DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL);
|
||||
|
||||
ThreadPoolExecutor executor = ThreadPools.getFileHandlerExecutor();
|
||||
if (executor == null || executor.isTerminated())
|
||||
{
|
||||
return;
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
// run file handling on a separate thread
|
||||
return CompletableFuture.runAsync(() -> this.updateDataSourcesRecursively(pos, chunkDataView), executor);
|
||||
}
|
||||
catch (RejectedExecutionException ignore)
|
||||
{
|
||||
// can happen if the executor was shutdown while this task was queued
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
/** Updates every data source from this position up to {@link AbstractDataSourceHandler#topSectionDetailLevelRef} */
|
||||
private void updateDataSourcesRecursively(DhSectionPos pos, ChunkSizedFullDataAccessor chunkDataView)
|
||||
{
|
||||
// update up until we reach the highest available data source
|
||||
if (pos.getDetailLevel() > this.topSectionDetailLevelRef.get())
|
||||
{
|
||||
@@ -203,23 +217,15 @@ public abstract class AbstractDataSourceHandler<TDataSource extends IDataSource<
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
executor.execute(() ->
|
||||
{
|
||||
DhSectionPos chunkSectionPos = chunkDataView.getSectionPos();
|
||||
LodUtil.assertTrue(chunkSectionPos.overlapsExactly(pos), "Update failed, chunk [" + chunkSectionPos + "] does not overlap section [" + pos + "].");
|
||||
|
||||
// update this pos
|
||||
this.updateDataSourceAtPos(pos, chunkDataView);
|
||||
|
||||
// recursively update the parent pos
|
||||
DhSectionPos parentPos = pos.getParentPos();
|
||||
this.recursivelyUpdateDataSourcesAsync(parentPos, chunkDataView);
|
||||
this.recursivelyUpdateDataSourcesAsync(parentPos, chunkDataView);
|
||||
});
|
||||
}
|
||||
catch (RejectedExecutionException ignore) { /* can happen if the executor was shutdown while this task was queued */ }
|
||||
DhSectionPos chunkSectionPos = chunkDataView.getSectionPos();
|
||||
LodUtil.assertTrue(chunkSectionPos.overlapsExactly(pos), "Update failed, chunk [" + chunkSectionPos + "] does not overlap section [" + pos + "].");
|
||||
|
||||
// update this pos
|
||||
this.updateDataSourceAtPos(pos, chunkDataView);
|
||||
|
||||
// recursively update the parent pos
|
||||
DhSectionPos parentPos = pos.getParentPos();
|
||||
this.updateDataSourcesRecursively(parentPos, chunkDataView);
|
||||
}
|
||||
protected void updateDataSourceAtPos(DhSectionPos pos, ChunkSizedFullDataAccessor chunkData)
|
||||
{
|
||||
@@ -286,6 +292,10 @@ public abstract class AbstractDataSourceHandler<TDataSource extends IDataSource<
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
|
||||
// remove this task from the queue
|
||||
AbstractDataSourceHandler.this.saveTimerTasksBySectionPos.remove(pos);
|
||||
|
||||
try
|
||||
{
|
||||
final TDataSource finalDataSource = AbstractDataSourceHandler.this.unsavedDataSourceBySectionPos.remove(pos);
|
||||
|
||||
@@ -10,6 +10,6 @@ public interface ISourceProvider<TDataSource extends IDataSource<TDhLevel>, TDhL
|
||||
{
|
||||
CompletableFuture<TDataSource> getAsync(DhSectionPos pos);
|
||||
|
||||
void updateDataSourcesWithChunkData(ChunkSizedFullDataAccessor chunkData);
|
||||
CompletableFuture<Void> updateDataSourcesWithChunkDataAsync(ChunkSizedFullDataAccessor chunkData);
|
||||
|
||||
}
|
||||
|
||||
+16
-20
@@ -31,6 +31,8 @@ import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.render.renderer.DebugRenderer;
|
||||
import com.seibel.distanthorizons.core.sql.AbstractDataSourceRepo;
|
||||
import com.seibel.distanthorizons.core.sql.FullDataRepo;
|
||||
import com.seibel.distanthorizons.core.sql.DataSourceDto;
|
||||
import com.seibel.distanthorizons.core.sql.FullDataRepo;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -69,17 +71,20 @@ public class FullDataFileHandler extends AbstractDataSourceHandler<IFullDataSour
|
||||
//=============//
|
||||
|
||||
public FullDataFileHandler(IDhLevel level, AbstractSaveStructure saveStructure) { this(level, saveStructure, null); }
|
||||
public FullDataFileHandler(IDhLevel level, AbstractSaveStructure saveStructure, @Nullable File saveDirOverride)
|
||||
public FullDataFileHandler(IDhLevel level, AbstractSaveStructure saveStructure, @Nullable File saveDirOverride) { super(level, saveStructure, saveDirOverride); }
|
||||
|
||||
|
||||
|
||||
//====================//
|
||||
// Abstract overrides //
|
||||
//====================//
|
||||
|
||||
@Override
|
||||
protected AbstractDataSourceRepo createRepo()
|
||||
{
|
||||
super(level, saveStructure, createRepo(level, saveStructure), saveDirOverride);
|
||||
}
|
||||
private static FullDataRepo createRepo(IDhLevel level, AbstractSaveStructure saveStructure)
|
||||
{
|
||||
File saveDir = saveStructure.getFullDataFolder(level.getLevelWrapper());
|
||||
|
||||
try
|
||||
{
|
||||
return new FullDataRepo("jdbc:sqlite", saveDir.getPath() + "/" + AbstractSaveStructure.DATABASE_NAME);
|
||||
return new FullDataRepo("jdbc:sqlite", this.saveDir.getPath() + "/" + AbstractSaveStructure.DATABASE_NAME);
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
@@ -89,12 +94,6 @@ public class FullDataFileHandler extends AbstractDataSourceHandler<IFullDataSour
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//====================//
|
||||
// Abstract overrides //
|
||||
//====================//
|
||||
|
||||
@Override
|
||||
protected IFullDataSource createDataSourceFromDto(DataSourceDto dto) throws InterruptedException, IOException
|
||||
{
|
||||
@@ -107,7 +106,6 @@ public class FullDataFileHandler extends AbstractDataSourceHandler<IFullDataSour
|
||||
protected IFullDataSource createNewDataSourceFromExistingDtos(DhSectionPos pos)
|
||||
{
|
||||
IIncompleteFullDataSource newFullDataSource = this.makeEmptyDataSource(pos);
|
||||
|
||||
|
||||
|
||||
boolean showFullDataFileSampling = Config.Client.Advanced.Debugging.DebugWireframe.showFullDataFileStatus.get();
|
||||
@@ -124,12 +122,12 @@ public class FullDataFileHandler extends AbstractDataSourceHandler<IFullDataSour
|
||||
ArrayList<DhSectionPos> possibleChildList = new ArrayList<>();
|
||||
pos.forEachChild((childPos) ->
|
||||
{
|
||||
if (childPos.getDetailLevel() > this.minDetailLevel)
|
||||
if (childPos.getDetailLevel() >= this.minDetailLevel)
|
||||
{
|
||||
possibleChildList.add(childPos);
|
||||
}
|
||||
});
|
||||
while (!possibleChildList.isEmpty())
|
||||
while (possibleChildList.size() != 0)
|
||||
{
|
||||
DhSectionPos possiblePos = possibleChildList.remove(possibleChildList.size()-1);
|
||||
if (this.repo.existsWithPrimaryKey(possiblePos.serialize()))
|
||||
@@ -140,7 +138,7 @@ public class FullDataFileHandler extends AbstractDataSourceHandler<IFullDataSour
|
||||
{
|
||||
possiblePos.forEachChild((childPos) ->
|
||||
{
|
||||
if (childPos.getDetailLevel() > this.minDetailLevel)
|
||||
if (childPos.getDetailLevel() >= this.minDetailLevel)
|
||||
{
|
||||
possibleChildList.add(childPos);
|
||||
}
|
||||
@@ -190,8 +188,6 @@ public class FullDataFileHandler extends AbstractDataSourceHandler<IFullDataSour
|
||||
LowDetailIncompleteFullDataSource.createEmpty(pos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//===================//
|
||||
|
||||
+2
-6
@@ -265,8 +265,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
{
|
||||
if (chunkSizedFullDataSource.getSectionPos().overlapsExactly(this.loadedTargetFullDataSource.getSectionPos()))
|
||||
{
|
||||
((DhLevel) level).updateDataSourcesWithChunkData(chunkSizedFullDataSource);
|
||||
//GeneratedFullDataFileHandler.this.write(this.loadedTargetFullDataSource.getSectionPos(), chunkSizedFullDataSource);
|
||||
((DhLevel) GeneratedFullDataFileHandler.this.level).updateDataSourcesWithChunkData(chunkSizedFullDataSource);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -275,10 +274,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* used by external event listeners <br>
|
||||
* TODO may or may not be best to have this in a separate file
|
||||
*/
|
||||
/** used by external event listeners */
|
||||
@FunctionalInterface
|
||||
public interface IOnWorldGenCompleteListener
|
||||
{
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ public interface IFullDataSourceProvider extends ISourceProvider<IFullDataSource
|
||||
CompletableFuture<IFullDataSource> getAsync(DhSectionPos pos);
|
||||
IFullDataSource get(DhSectionPos pos);
|
||||
|
||||
void updateDataSourcesWithChunkData(ChunkSizedFullDataAccessor chunkData);
|
||||
CompletableFuture<Void> updateDataSourcesWithChunkDataAsync(ChunkSizedFullDataAccessor chunkData);
|
||||
|
||||
int getUnsavedDataSourceCount();
|
||||
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ public interface IRenderSourceProvider extends ISourceProvider<ColumnRenderSourc
|
||||
{
|
||||
CompletableFuture<ColumnRenderSource> getAsync(DhSectionPos pos);
|
||||
|
||||
void updateDataSourcesWithChunkData(ChunkSizedFullDataAccessor chunkData);
|
||||
CompletableFuture<Void> updateDataSourcesWithChunkDataAsync(ChunkSizedFullDataAccessor chunkData);
|
||||
|
||||
/** Deletes any data stored in the render cache so it can be re-created */
|
||||
void deleteRenderCache();
|
||||
|
||||
+34
-13
@@ -25,13 +25,16 @@ import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSourceLoad
|
||||
import com.seibel.distanthorizons.core.dataObjects.transformers.FullDataToRenderDataTransformer;
|
||||
import com.seibel.distanthorizons.core.file.AbstractDataSourceHandler;
|
||||
import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.ColumnRenderSource;
|
||||
import com.seibel.distanthorizons.core.file.fullDatafile.IFullDataSourceProvider;
|
||||
import com.seibel.distanthorizons.core.level.IDhClientLevel;
|
||||
import com.seibel.distanthorizons.core.sql.AbstractDataSourceRepo;
|
||||
import com.seibel.distanthorizons.core.sql.DataSourceDto;
|
||||
import com.seibel.distanthorizons.core.sql.FullDataRepo;
|
||||
import com.seibel.distanthorizons.core.sql.RenderDataRepo;
|
||||
import com.seibel.distanthorizons.core.util.threading.ThreadPools;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -58,18 +61,39 @@ public class RenderSourceFileHandler extends AbstractDataSourceHandler<ColumnRen
|
||||
|
||||
public RenderSourceFileHandler(IFullDataSourceProvider sourceProvider, IDhClientLevel clientLevel, AbstractSaveStructure saveStructure)
|
||||
{
|
||||
super(clientLevel, saveStructure, createRepo(clientLevel, saveStructure));
|
||||
super(clientLevel, saveStructure);
|
||||
|
||||
this.fullDataSourceProvider = sourceProvider;
|
||||
this.threadPoolMsg = new F3Screen.NestedMessage(this::f3Log);
|
||||
}
|
||||
private static RenderDataRepo createRepo(IDhClientLevel clientLevel, AbstractSaveStructure saveStructure)
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// overrides //
|
||||
//===========//
|
||||
|
||||
@Override
|
||||
public ColumnRenderSource get(DhSectionPos pos)
|
||||
{
|
||||
File saveDir = saveStructure.getRenderCacheFolder(clientLevel.getLevelWrapper());
|
||||
// call the full data provider to make sure the full data is up to date
|
||||
// and any necessary world generation has been queued/completed
|
||||
this.fullDataSourceProvider.get(pos);
|
||||
|
||||
return super.get(pos);
|
||||
}
|
||||
|
||||
|
||||
//====================//
|
||||
// Abstract overrides //
|
||||
//====================//
|
||||
|
||||
@Override
|
||||
protected AbstractDataSourceRepo createRepo()
|
||||
{
|
||||
try
|
||||
{
|
||||
return new RenderDataRepo("jdbc:sqlite", saveDir.getPath() + "/" + AbstractSaveStructure.DATABASE_NAME);
|
||||
return new RenderDataRepo("jdbc:sqlite", this.saveDir.getPath() + "/" + AbstractSaveStructure.DATABASE_NAME);
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
@@ -79,12 +103,6 @@ public class RenderSourceFileHandler extends AbstractDataSourceHandler<ColumnRen
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//====================//
|
||||
// Abstract overrides //
|
||||
//====================//
|
||||
|
||||
@Override
|
||||
protected ColumnRenderSource createDataSourceFromDto(DataSourceDto dto) throws InterruptedException, IOException
|
||||
{ return ColumnRenderSourceLoader.INSTANCE.loadRenderSource(dto, dto.getInputStream(), this.level); }
|
||||
@@ -132,10 +150,13 @@ public class RenderSourceFileHandler extends AbstractDataSourceHandler<ColumnRen
|
||||
return lines.toArray(new String[0]);
|
||||
}
|
||||
|
||||
public void updateDataSourcesWithChunkData(ChunkSizedFullDataAccessor chunkDataView)
|
||||
@Override
|
||||
public CompletableFuture<Void> updateDataSourcesWithChunkDataAsync(ChunkSizedFullDataAccessor chunkDataView)
|
||||
{
|
||||
super.updateDataSourcesWithChunkData(chunkDataView);
|
||||
this.fullDataSourceProvider.updateDataSourcesWithChunkData(chunkDataView);
|
||||
return CompletableFuture.allOf(
|
||||
super.updateDataSourcesWithChunkDataAsync(chunkDataView),
|
||||
this.fullDataSourceProvider.updateDataSourcesWithChunkDataAsync(chunkDataView)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class ClientLevelModule implements Closeable
|
||||
@@ -181,12 +182,14 @@ public class ClientLevelModule implements Closeable
|
||||
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
|
||||
if (ClientRenderState != null)
|
||||
{
|
||||
ClientRenderState.renderSourceFileHandler.updateDataSourcesWithChunkData(data);
|
||||
ClientRenderState.quadtree.reloadPos(data.sectionPos);
|
||||
ClientRenderState.renderSourceFileHandler
|
||||
.updateDataSourcesWithChunkDataAsync(data)
|
||||
// wait for the update to finish before triggering a reload to prevent holes in the world
|
||||
.thenRun(() -> ClientRenderState.quadtree.reloadPos(data.sectionPos));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.parentClientLevel.getFileHandler().updateDataSourcesWithChunkData(data);
|
||||
this.parentClientLevel.getFileHandler().updateDataSourcesWithChunkDataAsync(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel
|
||||
{
|
||||
DhSectionPos pos = data.getSectionPos();
|
||||
pos = pos.convertNewToDetailLevel(CompleteFullDataSource.SECTION_SIZE_OFFSET);
|
||||
this.getFileHandler().updateDataSourcesWithChunkData(data);
|
||||
this.getFileHandler().updateDataSourcesWithChunkDataAsync(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,10 +19,13 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.render;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.pos.Pos2D;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
|
||||
import com.seibel.distanthorizons.core.util.objects.quadTree.QuadNode;
|
||||
import com.seibel.distanthorizons.core.render.renderer.LodRenderer;
|
||||
@@ -38,7 +41,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* This object tells the {@link LodRenderer} what buffers to render
|
||||
* TODO rename this class, maybe RenderBufferOrganizer or something more specific?
|
||||
*/
|
||||
public class RenderBufferHandler
|
||||
public class RenderBufferHandler implements AutoCloseable
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
@@ -50,8 +53,20 @@ public class RenderBufferHandler
|
||||
|
||||
private final AtomicBoolean rebuildAllBuffers = new AtomicBoolean(false);
|
||||
|
||||
public F3Screen.DynamicMessage f3Message;
|
||||
|
||||
public RenderBufferHandler(LodQuadTree lodQuadTree) { this.lodQuadTree = lodQuadTree; }
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public RenderBufferHandler(LodQuadTree lodQuadTree)
|
||||
{
|
||||
this.lodQuadTree = lodQuadTree;
|
||||
|
||||
this.f3Message = new F3Screen.DynamicMessage(() -> LodUtil.formatLog("Rendered Buffer Count: " + this.loadedNearToFarBuffers.size()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -227,6 +242,12 @@ public class RenderBufferHandler
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// cleanup //
|
||||
//=========//
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
Iterator<QuadNode<LodRenderSection>> nodeIterator = this.lodQuadTree.nodeIterator();
|
||||
|
||||
@@ -47,10 +47,10 @@ import java.io.PrintStream;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* A singleton that holds references to different openGL contexts
|
||||
@@ -65,15 +65,11 @@ import java.util.stream.Stream;
|
||||
*
|
||||
* https://gamedev.stackexchange.com/questions/91995/edit-vbo-data-or-create-a-new-one <br>
|
||||
* https://stackoverflow.com/questions/63509735/massive-performance-loss-with-glmapbuffer <br><br>
|
||||
*
|
||||
* @author James Seibel
|
||||
*/
|
||||
public class GLProxy
|
||||
{
|
||||
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
|
||||
private ExecutorService workerThread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(GLProxy.class.getSimpleName() + "-Worker-Thread").build());
|
||||
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
public static final ConfigBasedLogger GL_LOGGER = new ConfigBasedLogger(LogManager.getLogger(GLProxy.class),
|
||||
() -> Config.Client.Advanced.Logging.logRendererGLEvent.get());
|
||||
@@ -88,6 +84,10 @@ public class GLProxy
|
||||
private static GLProxy instance = null;
|
||||
|
||||
|
||||
private ExecutorService workerThread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(GLProxy.class.getSimpleName() + "-Worker-Thread").build());
|
||||
|
||||
private ConcurrentLinkedQueue<Runnable> renderThreadRunnableQueue = new ConcurrentLinkedQueue<>();
|
||||
|
||||
/** Minecraft's GLFW window */
|
||||
public final long minecraftGlContext;
|
||||
/** Minecraft's GL capabilities */
|
||||
@@ -459,9 +459,9 @@ public class GLProxy
|
||||
|
||||
|
||||
|
||||
//============================//
|
||||
// MC render thread runnables //
|
||||
//============================//
|
||||
//=========================//
|
||||
// Worker Thread Runnables //
|
||||
//=========================//
|
||||
|
||||
/**
|
||||
* Asynchronously calls the given runnable on proxy's OpenGL context.
|
||||
@@ -472,14 +472,18 @@ public class GLProxy
|
||||
public void recordOpenGlCall(Runnable renderCall)
|
||||
{
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
this.workerThread.execute(() -> this.runnableContainer(renderCall, stackTrace));
|
||||
this.workerThread.execute(() -> this.runOpenGlCall(renderCall, stackTrace, true));
|
||||
}
|
||||
private void runnableContainer(Runnable renderCall, StackTraceElement[] stackTrace)
|
||||
private void runOpenGlCall(Runnable renderCall, StackTraceElement[] stackTrace, boolean useProxyWorkerContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
// set up the context...
|
||||
this.setGlContext(EGLProxyContext.PROXY_WORKER);
|
||||
// set up the context if requested...
|
||||
if (useProxyWorkerContext)
|
||||
{
|
||||
this.setGlContext(EGLProxyContext.PROXY_WORKER);
|
||||
}
|
||||
|
||||
// ...run the actual code...
|
||||
renderCall.run();
|
||||
}
|
||||
@@ -492,7 +496,10 @@ public class GLProxy
|
||||
finally
|
||||
{
|
||||
// ...and make sure the context is released when the thread finishes
|
||||
this.setGlContext(EGLProxyContext.NONE);
|
||||
if (useProxyWorkerContext)
|
||||
{
|
||||
this.setGlContext(EGLProxyContext.NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,6 +535,32 @@ public class GLProxy
|
||||
|
||||
|
||||
|
||||
//=========================//
|
||||
// Render Thread Runnables //
|
||||
//=========================//
|
||||
|
||||
public void queueRunningOnRenderThread(Runnable renderCall)
|
||||
{
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
this.renderThreadRunnableQueue.add(() -> this.runOpenGlCall(renderCall, stackTrace, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Doesn't do any thread/GL Context validation.
|
||||
* Running this outside of the render thread may cause crashes or other issues.
|
||||
*/
|
||||
public void runRenderThreadTasks()
|
||||
{
|
||||
Runnable runnable = this.renderThreadRunnableQueue.poll();
|
||||
while(runnable != null)
|
||||
{
|
||||
runnable.run();
|
||||
runnable = this.renderThreadRunnableQueue.poll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// logging //
|
||||
//=========//
|
||||
|
||||
+7
-4
@@ -122,9 +122,12 @@ public class GLBuffer implements AutoCloseable
|
||||
}
|
||||
private static void destroyBufferId(boolean async, int id)
|
||||
{
|
||||
if (async && GLProxy.getInstance().getGlContext() != EGLProxyContext.PROXY_WORKER)
|
||||
EGLProxyContext glContext = GLProxy.getInstance().getGlContext();
|
||||
if (async
|
||||
&& glContext != EGLProxyContext.PROXY_WORKER
|
||||
&& glContext != EGLProxyContext.MINECRAFT)
|
||||
{
|
||||
GLProxy.getInstance().recordOpenGlCall(() -> destroyBufferId(false, id));
|
||||
GLProxy.getInstance().queueRunningOnRenderThread(() -> destroyBufferId(false, id));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -200,7 +203,7 @@ public class GLBuffer implements AutoCloseable
|
||||
LodUtil.assertTrue(this.bufferStorage, "Buffer is not bufferStorage but its trying to use bufferStorage upload method!");
|
||||
|
||||
int bbSize = bb.limit() - bb.position();
|
||||
this.destroy(false);
|
||||
this.destroy(true);
|
||||
this.create(true);
|
||||
this.bind();
|
||||
GL44.glBufferStorage(this.getBufferBindingTarget(), bb, bufferStorageHint);
|
||||
@@ -313,7 +316,7 @@ public class GLBuffer implements AutoCloseable
|
||||
{
|
||||
// recreate if the buffer storage type changed
|
||||
this.bind();
|
||||
this.destroy(false);
|
||||
this.destroy(true);
|
||||
this.create(uploadMethod.useBufferStorage);
|
||||
this.bind();
|
||||
}
|
||||
|
||||
@@ -486,6 +486,9 @@ public class LodRenderer
|
||||
|
||||
profiler.popPush("LOD cleanup");
|
||||
LagSpikeCatcher drawCleanup = new LagSpikeCatcher();
|
||||
|
||||
GLProxy.getInstance().runRenderThreadTasks();
|
||||
|
||||
lightmap.unbind();
|
||||
if (ENABLE_IBO)
|
||||
{
|
||||
@@ -666,7 +669,7 @@ public class LodRenderer
|
||||
this.setupLock.lock();
|
||||
|
||||
EVENT_LOGGER.info("Queuing Renderer Cleanup for main render thread");
|
||||
GLProxy.getInstance().recordOpenGlCall(() ->
|
||||
GLProxy.getInstance().queueRunningOnRenderThread(() ->
|
||||
{
|
||||
EVENT_LOGGER.info("Renderer Cleanup Started");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user