refactor and comment

This commit is contained in:
James Seibel
2023-07-31 20:43:35 -05:00
parent e58b1fffed
commit 3179ba0db8
4 changed files with 171 additions and 104 deletions
@@ -53,7 +53,9 @@ public class ColumnRenderBufferBuilder
// vbo building //
//==============//
public static CompletableFuture<ColumnRenderBuffer> buildBuffers(IDhClientLevel clientLevel, Reference<ColumnRenderBuffer> renderBufferRef, ColumnRenderSource renderSource, ColumnRenderSource[] adjData)
public static CompletableFuture<ColumnRenderBuffer> buildBuffersAsync(
IDhClientLevel clientLevel, Reference<ColumnRenderBuffer> renderBufferRef,
ColumnRenderSource renderSource, ColumnRenderSource[] adjData)
{
/* if (isBusy())
{
@@ -278,11 +278,11 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider
{
return metaFile; // someone else loaded it already.
}
try
{
metaFile = RenderMetaDataFile.createFromExistingFile(this, fileToLoad);
this.topDetailLevel.updateAndGet(v -> Math.max(v, pos.sectionDetailLevel));
this.topDetailLevel.updateAndGet(newDetailLevel -> Math.max(newDetailLevel, pos.sectionDetailLevel));
this.filesBySectionPos.put(pos, metaFile);
return metaFile;
}
@@ -317,7 +317,7 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider
return null;
}
this.topDetailLevel.updateAndGet(v -> Math.max(v, pos.sectionDetailLevel));
this.topDetailLevel.updateAndGet(newDetailLevel -> Math.max(newDetailLevel, pos.sectionDetailLevel));
// This is a CAS with expected null value.
RenderMetaDataFile metaFileCas = this.filesBySectionPos.putIfAbsent(pos, metaFile);
return metaFileCas == null ? metaFile : metaFileCas;
@@ -336,7 +336,10 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider
RenderMetaDataFile metaFile = this.getLoadOrMakeFile(pos, true);
// On error, (when it returns null,) return an empty render source
if (metaFile == null) return CompletableFuture.completedFuture(ColumnRenderSource.createEmptyRenderSource(pos));
if (metaFile == null)
{
return CompletableFuture.completedFuture(ColumnRenderSource.createEmptyRenderSource(pos));
}
CompletableFuture<ColumnRenderSource> future = metaFile.loadOrGetCachedDataSourceAsync(this.fileHandlerThreadPool, this.level).handle(
(renderSource, exception) ->
@@ -348,8 +351,10 @@ public class RenderSourceFileHandler implements ILodRenderSourceProvider
return (renderSource != null) ? renderSource : ColumnRenderSource.createEmptyRenderSource(pos);
});
synchronized (taskTracker) {
taskTracker.put(future, TaskType.Read);
synchronized (this.taskTracker)
{
this.taskTracker.put(future, TaskType.Read);
}
return future;
}
@@ -60,18 +60,25 @@ public class LodRenderSection implements IDebugRenderable
/** a reference is used so the render buffer can be swapped to and from the buffer builder */
public final AtomicReference<ColumnRenderBuffer> activeRenderBufferRef = new AtomicReference<>();
private volatile boolean doDisposeActiveBuffer = false;
private volatile boolean disposeActiveBuffer = false;
private final QuadTree<LodRenderSection> parentQuadTree;
public LodRenderSection(QuadTree<LodRenderSection> parentQuadTree, DhSectionPos pos) {
//=============//
// constructor //
//=============//
public LodRenderSection(QuadTree<LodRenderSection> parentQuadTree, DhSectionPos pos)
{
this.pos = pos;
this.parentQuadTree = parentQuadTree;
DebugRenderer.register(this);
}
public void debugRender(DebugRenderer r)
public void debugRender(DebugRenderer debugRenderer)
{
Color color = Color.red;
@@ -86,7 +93,7 @@ public class LodRenderSection implements IDebugRenderable
if (canRenderNow() && isRenderingEnabled) color = Color.green;
}
r.renderBox(new DebugRenderer.Box(this.pos, 400, 8f, Objects.hashCode(this), 0.1f, color));
debugRenderer.renderBox(new DebugRenderer.Box(this.pos, 400, 8f, Objects.hashCode(this), 0.1f, color));
}
@@ -95,32 +102,17 @@ public class LodRenderSection implements IDebugRenderable
// rendering //
//===========//
public void enableRendering() {
public void enableRendering()
{
this.isRenderingEnabled = true;
}
public void disableRendering() {
this.isRenderingEnabled = false;
}
public void disableRendering() { this.isRenderingEnabled = false; }
//=============//
// render data //
//=============//
private void startLoadRenderSource() {
this.renderSourceLoadFuture = this.renderSourceProvider.readAsync(this.pos);
this.renderSourceLoadFuture.whenComplete((renderSource, ex) ->
{
this.renderSourceLoadFuture = null;
this.renderSource = renderSource;
this.lastNs = -1;
markBufferDirty();
if (this.reloadRenderSourceOnceLoaded)
{
this.reloadRenderSourceOnceLoaded = false;
reload(this.renderSourceProvider);
}
});
}
/** does nothing if a render source is already loaded or in the process of loading */
public void loadRenderSource(ILodRenderSourceProvider renderDataProvider, IDhClientLevel level)
@@ -129,6 +121,7 @@ public class LodRenderSection implements IDebugRenderable
this.level = level;
if (this.renderSourceProvider == null)
{
LOGGER.warn("LodRenderSection ["+this.pos+"] called loadRenderSource with a empty source provider");
return;
}
// don't re-load or double load the render source
@@ -136,23 +129,31 @@ public class LodRenderSection implements IDebugRenderable
{
return;
}
startLoadRenderSource();
this.startLoadRenderSourceAsync();
}
public void reload(ILodRenderSourceProvider renderDataProvider)
{
if (pos.sectionDetailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
// debug rendering
if (this.pos.sectionDetailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
{
DebugRenderer.makeParticle(
new DebugRenderer.BoxParticle(
new DebugRenderer.Box(pos, 0, 256f, 0.03f, Color.cyan),
0.5, 512f
)
);
}
this.renderSourceProvider = renderDataProvider;
if (this.renderSourceProvider == null)
{
LOGGER.warn("LodRenderSection ["+this.pos+"] called reload with a empty source provider");
return;
}
// don't accidentally enable rendering for a disabled section
if (!this.isRenderingEnabled)
{
@@ -161,16 +162,33 @@ public class LodRenderSection implements IDebugRenderable
// wait for the current load future to finish before re-loading
if (this.renderSourceLoadFuture != null)
{
reloadRenderSourceOnceLoaded = true;
this.reloadRenderSourceOnceLoaded = true;
return;
}
startLoadRenderSource();
this.startLoadRenderSourceAsync();
}
private void startLoadRenderSourceAsync()
{
this.renderSourceLoadFuture = this.renderSourceProvider.readAsync(this.pos);
this.renderSourceLoadFuture.whenComplete((renderSource, ex) ->
{
this.renderSource = renderSource;
this.lastNs = -1;
this.markBufferDirty();
if (this.reloadRenderSourceOnceLoaded)
{
this.reloadRenderSourceOnceLoaded = false;
this.reload(this.renderSourceProvider);
}
this.renderSourceLoadFuture = null;
});
}
//========================//
// getters and properties //
//========================//
@@ -182,6 +200,12 @@ public class LodRenderSection implements IDebugRenderable
public boolean canRenderNow()
{
if (this.renderSourceLoadFuture != null || this.buildRenderBufferFuture != null)
{
// wait for loading to finish
return false;
}
return this.renderSource != null
&&
(
@@ -210,46 +234,44 @@ public class LodRenderSection implements IDebugRenderable
this.buildRenderBufferFuture = null;
}
}
private boolean isBufferOutdated() {
//if (this.lastNs == -1) return false;
/* boolean inTimeout = System.nanoTime() - this.lastNs < SWAP_TIMEOUT_IN_NS;
if (!inTimeout && ColumnRenderBufferBuilder.isBusy()) {
this.lastNs += (long) (SWAP_BUSY_COLLISION_TIMEOUT_IN_NS * Math.random());
return true;
}*/
return neighborUpdated || renderSource.localVersion.get() - lastSwapLocalVersion > 0;
}
private LodRenderSection[] getNeighbors()
{
LodRenderSection[] adjacents = new LodRenderSection[EDhDirection.ADJ_DIRECTIONS.length];
for (EDhDirection direction : EDhDirection.ADJ_DIRECTIONS) {
try {
DhSectionPos adjPos = pos.getAdjacentPos(direction);
LodRenderSection adjRenderSection = parentQuadTree.getValue(adjPos);
LodRenderSection[] adjacentRenderSections = new LodRenderSection[EDhDirection.ADJ_DIRECTIONS.length];
for (EDhDirection direction : EDhDirection.ADJ_DIRECTIONS)
{
try
{
DhSectionPos adjPos = this.pos.getAdjacentPos(direction);
LodRenderSection adjRenderSection = this.parentQuadTree.getValue(adjPos);
// adjacent render sources might be null
adjacents[direction.ordinal() - 2] = adjRenderSection;
} catch (IndexOutOfBoundsException e) {
adjacentRenderSections[direction.ordinal() - 2] = adjRenderSection;
}
catch (IndexOutOfBoundsException e)
{
// adjacent positions can be out of bounds, in that case a null render source will be used
}
}
return adjacents;
return adjacentRenderSections;
}
private void tellNeighborsUpdated()
{
LodRenderSection[] adjacents = getNeighbors();
for (LodRenderSection adj : adjacents) {
if (adj != null) {
LodRenderSection[] adjacentRenderSections = this.getNeighbors();
for (LodRenderSection adj : adjacentRenderSections)
{
if (adj != null)
{
adj.neighborUpdated = true;
}
}
}
/** @return true if this section is loaded and set to render */
public boolean canBuildBuffer() { return this.renderSource != null && this.buildRenderBufferFuture == null && !this.renderSource.isEmpty() && isBufferOutdated(); }
public boolean canBuildBuffer() { return this.renderSource != null && this.buildRenderBufferFuture == null && !this.renderSource.isEmpty() && this.isBufferOutdated(); }
private boolean isBufferOutdated() { return this.neighborUpdated || (this.renderSource.localVersion.get() - this.lastSwapLocalVersion) > 0; }
/** @return true if this section is loaded and set to render */
public boolean canSwapBuffer() { return this.buildRenderBufferFuture != null && this.buildRenderBufferFuture.isDone(); }
@@ -262,49 +284,71 @@ public class LodRenderSection implements IDebugRenderable
*/
public boolean tryBuildAndSwapBuffer()
{
if (doDisposeActiveBuffer && this.activeRenderBufferRef.get() != null) {
doDisposeActiveBuffer = false;
// delete the existing buffer if it should be disposed
if (this.disposeActiveBuffer && this.activeRenderBufferRef.get() != null)
{
this.disposeActiveBuffer = false;
this.activeRenderBufferRef.getAndSet(null).close();
return false;
}
// attempt to build the buffer
boolean didSwapped = false;
if (canBuildBuffer()) {
//if (false)
if (pos.sectionDetailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
if (this.canBuildBuffer())
{
// debug
if (this.pos.sectionDetailLevel == DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL)
{
DebugRenderer.makeParticle(
new DebugRenderer.BoxParticle(
new DebugRenderer.Box(pos, 32f, 64f, 0.2f, Color.yellow),
0.5, 16f
)
new DebugRenderer.BoxParticle(
new DebugRenderer.Box(this.pos, 32f, 64f, 0.2f, Color.yellow),
0.5, 16f
)
);
neighborUpdated = false;
long newVs = renderSource.localVersion.get();
if (lastSwapLocalVersion != newVs) {
lastSwapLocalVersion = newVs;
tellNeighborsUpdated();
}
LodRenderSection[] adjacents = getNeighbors();
this.neighborUpdated = false;
long newVersion = this.renderSource.localVersion.get();
if (this.lastSwapLocalVersion != newVersion)
{
this.lastSwapLocalVersion = newVersion;
this.tellNeighborsUpdated();
}
LodRenderSection[] adjacentRenderSections = this.getNeighbors();
ColumnRenderSource[] adjacentSources = new ColumnRenderSource[EDhDirection.ADJ_DIRECTIONS.length];
for (int i = 0; i < EDhDirection.ADJ_DIRECTIONS.length; i++) {
LodRenderSection adj = adjacents[i];
if (adj != null) {
for (int i = 0; i < EDhDirection.ADJ_DIRECTIONS.length; i++)
{
LodRenderSection adj = adjacentRenderSections[i];
if (adj != null)
{
adjacentSources[i] = adj.getRenderSource();
}
}
this.buildRenderBufferFuture = ColumnRenderBufferBuilder.buildBuffers(level, this.inactiveRenderBufferRef, renderSource, adjacentSources);
this.buildRenderBufferFuture = ColumnRenderBufferBuilder.buildBuffersAsync(this.level, this.inactiveRenderBufferRef, this.renderSource, adjacentSources);
}
if (canSwapBuffer()) {
// attempt to swap in the buffer
if (this.canSwapBuffer())
{
this.lastNs = System.nanoTime();
ColumnRenderBuffer newBuffer;
try {
try
{
newBuffer = this.buildRenderBufferFuture.getNow(null);
this.buildRenderBufferFuture = null;
if (newBuffer == null) {
if (newBuffer == null)
{
// failed.
markBufferDirty();
this.markBufferDirty();
return false;
}
LodUtil.assertTrue(newBuffer.buffersUploaded, "The buffer future for "+pos+" returned an un-built buffer.");
LodUtil.assertTrue(newBuffer.buffersUploaded, "The buffer future for "+this.pos+" returned an un-built buffer.");
ColumnRenderBuffer oldBuffer = this.activeRenderBufferRef.getAndSet(newBuffer);
if (oldBuffer != null)
{
@@ -315,23 +359,33 @@ public class LodRenderSection implements IDebugRenderable
didSwapped = true;
LodUtil.assertTrue(swapped == null);
}
catch (CancellationException e1) {
catch (CancellationException e1)
{
// ignore.
this.buildRenderBufferFuture = null;
}
catch (CompletionException e) {
LOGGER.error("Unable to get render buffer for "+pos+".", e);
catch (CompletionException e)
{
LOGGER.error("Unable to get render buffer for " + pos + ".", e);
this.buildRenderBufferFuture = null;
}
finally
{
this.buildRenderBufferFuture = null;
}
}
return didSwapped;
}
//==============//
// base methods //
//==============//
public String toString() {
public String toString()
{
return "LodRenderSection{" +
"pos=" + this.pos +
", lodRenderSource=" + this.renderSource +
@@ -340,17 +394,19 @@ public class LodRenderSection implements IDebugRenderable
'}';
}
public void dispose() {
disposeRenderData();
public void dispose()
{
this.disposeRenderData();
DebugRenderer.unregister(this);
if (doDisposeActiveBuffer && this.activeRenderBufferRef.get() != null) {
if (this.disposeActiveBuffer && this.activeRenderBufferRef.get() != null)
{
this.activeRenderBufferRef.get().close();
}
}
public synchronized void disposeRenderData() // synchronized is a band-aid solution to prevent a rare bug where the future isn't canceled in the right order
{
disposeRenderBuffer();
this.disposeRenderBuffer();
this.renderSource = null;
if (this.renderSourceLoadFuture != null)
{
@@ -361,11 +417,10 @@ public class LodRenderSection implements IDebugRenderable
public void disposeRenderBuffer()
{
cancelBuildBuffer();
doDisposeActiveBuffer = true;
this.cancelBuildBuffer();
this.disposeActiveBuffer = true;
}
public void markBufferDirty() {
lastSwapLocalVersion = -1;
}
public void markBufferDirty() { this.lastSwapLocalVersion = -1; }
}
@@ -156,17 +156,22 @@ public class RenderBufferHandler
DhSectionPos sectionPos = node.sectionPos;
LodRenderSection renderSection = node.value;
try {
try
{
if (renderSection != null) {
if (rebuildAllBuffers) {
if (renderSection != null)
{
if (rebuildAllBuffers)
{
renderSection.markBufferDirty();
}
renderSection.tryBuildAndSwapBuffer();
if (renderSection.isRenderingEnabled()) {
if (renderSection.isRenderingEnabled())
{
AbstractRenderBuffer buffer = renderSection.activeRenderBufferRef.get();
if (buffer != null) {
if (buffer != null)
{
this.loadedNearToFarBuffers.add(new LoadedRenderBuffer(buffer, sectionPos));
}
}