diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java index 0aaa4b94a..341cb9f3f 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java @@ -1252,6 +1252,11 @@ public class Config .comment("Render LOD section status?") .build(); + public static ConfigEntry showQuadTreeRenderStatus = new ConfigEntry.Builder() + .set(false) + .comment("Render Quad Tree Rendering status?") + .build(); + public static ConfigEntry showFullDataUpdateStatus = new ConfigEntry.Builder() .set(false) .comment("Render full data update/lock status?") diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java index 05eb3b340..755b6b91c 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java @@ -343,17 +343,24 @@ public class ColumnRenderBuffer implements AutoCloseable //==============// /** can be used when debugging */ - public boolean hasNonEmptyBuffers() + public boolean hasNonNullVbos() { return this.vbos != null || this.vbosTransparent != null; } + + /** can be used when debugging */ + public int vboBufferCount() { - for (GLVertexBuffer vertexBuffer : this.vbos) + int count = 0; + + if (this.vbos != null) { - if (vertexBuffer != null && vertexBuffer.getSize() != 0) - { - return true; - } + count += this.vbos.length; } - return false; + if (this.vbosTransparent != null) + { + count += this.vbosTransparent.length; + } + + return count; } public void debugDumpStats(StatsMap statsMap) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java index 391d834ee..681aba2c1 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/LodQuadTree.java @@ -30,6 +30,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhBlockPos2D; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.render.renderer.DebugRenderer; +import com.seibel.distanthorizons.core.render.renderer.IDebugRenderable; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.ThreadUtil; import com.seibel.distanthorizons.core.util.objects.quadTree.QuadNode; @@ -42,6 +43,7 @@ import javax.annotation.WillNotClose; import java.awt.*; import java.util.ArrayList; import java.util.Iterator; +import java.util.Objects; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.atomic.AtomicBoolean; @@ -51,7 +53,7 @@ import java.util.concurrent.locks.ReentrantLock; * This quadTree structure is our core data structure and holds * all rendering data. */ -public class LodQuadTree extends QuadTree implements AutoCloseable +public class LodQuadTree extends QuadTree implements IDebugRenderable, AutoCloseable { public static final byte TREE_LOWEST_DETAIL_LEVEL = ColumnRenderSource.SECTION_SIZE_OFFSET; @@ -75,6 +77,10 @@ public class LodQuadTree extends QuadTree implements AutoClose private final ReentrantLock treeReadWriteLock = new ReentrantLock(); private final AtomicBoolean fullDataRetrievalQueueRunning = new AtomicBoolean(false); + private ArrayList debugRenderSections = new ArrayList<>(); + private ArrayList altDebugRenderSections = new ArrayList<>(); + private final ReentrantLock debugRenderSectionLock = new ReentrantLock(); + /** the smallest numerical detail level number that can be rendered */ private byte maxRenderDetailLevel; /** the largest numerical detail level number that can be rendered */ @@ -98,6 +104,8 @@ public class LodQuadTree extends QuadTree implements AutoClose { super(viewDiameterInBlocks, new DhBlockPos2D(initialPlayerBlockX, initialPlayerBlockZ), TREE_LOWEST_DETAIL_LEVEL); + DebugRenderer.register(this, Config.Client.Advanced.Debugging.DebugWireframe.showQuadTreeRenderStatus); + this.level = level; this.fullDataSourceProvider = fullDataSourceProvider; this.blockRenderDistanceDiameter = viewDiameterInBlocks; @@ -152,6 +160,26 @@ public class LodQuadTree extends QuadTree implements AutoClose } private void updateAllRenderSections(DhBlockPos2D playerPos) { + if (Config.Client.Advanced.Debugging.DebugWireframe.showQuadTreeRenderStatus.get()) + { + try + { + // lock to prevent accidentally rendering an array that's being populated/cleared + this.debugRenderSectionLock.lock(); + + // swap the debug arrays + this.debugRenderSections.clear(); + ArrayList temp = this.debugRenderSections; + this.debugRenderSections = this.altDebugRenderSections; + this.altDebugRenderSections = temp; + } + finally + { + this.debugRenderSectionLock.unlock(); + } + } + + // reload any sections that need it DhSectionPos pos; while ((pos = this.sectionsToReload.poll()) != null) @@ -349,6 +377,11 @@ public class LodQuadTree extends QuadTree implements AutoClose nodesNeedingLoading.add(renderSection); } + if (Config.Client.Advanced.Debugging.DebugWireframe.showQuadTreeRenderStatus.get()) + { + this.debugRenderSections.add(renderSection); + } + // wait for the parent to disable before enabling this section, so we don't overdraw/overlap render sections if (!parentSectionIsRendering && renderSection.canRender()) { @@ -593,6 +626,56 @@ public class LodQuadTree extends QuadTree implements AutoClose private void onHorizontalQualityChange() { this.clearRenderDataCache(); } + //===========// + // debugging // + //===========// + + @Override + public void debugRender(DebugRenderer debugRenderer) + { + try + { + // lock to prevent accidentally rendering the array that's being cleared + this.debugRenderSectionLock.lock(); + + + for (int i = 0; i < this.debugRenderSections.size(); i++) + { + LodRenderSection renderSection = this.debugRenderSections.get(i); + + Color color = Color.BLACK; + if (renderSection.gpuUploadInProgress()) + { + color = Color.ORANGE; + } + else if (renderSection.renderBuffer == null) + { + // uploaded but the buffer is missing + color = Color.PINK; + } + else if (renderSection.renderBuffer.hasNonNullVbos()) + { + if (renderSection.renderBuffer.vboBufferCount() != 0) + { + color = Color.GREEN; + } + else + { + // This section is probably rendering an empty chunk + color = Color.RED; + } + } + + debugRenderer.renderBox(new DebugRenderer.Box(renderSection.pos, 400, 400f, Objects.hashCode(this), 0.05f, color)); + } + } + finally + { + this.debugRenderSectionLock.unlock(); + } + } + + //==============// // base methods // @@ -605,6 +688,8 @@ public class LodQuadTree extends QuadTree implements AutoClose this.horizontalScaleChangeListener.close(); + DebugRenderer.unregister(this, Config.Client.Advanced.Debugging.DebugWireframe.showQuadTreeRenderStatus); + Iterator> nodeIterator = this.nodeIterator(); while (nodeIterator.hasNext()) { diff --git a/core/src/main/resources/assets/distanthorizons/lang/en_us.json b/core/src/main/resources/assets/distanthorizons/lang/en_us.json index ddd0b7127..d1ee62c9d 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -573,6 +573,8 @@ "Show World Gen Queue", "distanthorizons.config.client.advanced.debugging.debugWireframe.showRenderSectionStatus": "Show Render Section Status", + "distanthorizons.config.client.advanced.debugging.debugWireframe.showQuadTreeRenderStatus": + "Show Quad Tree Render Status", "distanthorizons.config.client.advanced.debugging.debugWireframe.showFullDataUpdateStatus": "Show Full Data Update Status",