From ecdd0403c1ee5c78787cc4c2add0640273c8170d Mon Sep 17 00:00:00 2001 From: douira Date: Mon, 2 Dec 2024 04:09:20 +0100 Subject: [PATCH] fix some issues with very delayed section sorting. There are still other issues with (at least vertical) sorting though and even important zero-frame blocking tasks are not scheduled within the same frame --- .../render/chunk/RenderSectionManager.java | 40 +++++++++++++------ .../render/chunk/lists/TaskSectionTree.java | 19 +++++---- .../render/chunk/tree/BaseBiForest.java | 14 +++---- 3 files changed, 47 insertions(+), 26 deletions(-) diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager.java index 6316584f69..f4eef48b50 100644 --- a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager.java +++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager.java @@ -110,11 +110,7 @@ public class RenderSectionManager { private @Nullable BlockPos cameraBlockPos; private @Nullable Vector3dc cameraPosition; - private final ExecutorService asyncCullExecutor = Executors.newSingleThreadExecutor(runnable -> { - Thread thread = new Thread(runnable); - thread.setName("Sodium Async Cull Thread"); - return thread; - }); + private final ExecutorService asyncCullExecutor = Executors.newSingleThreadExecutor(RenderSectionManager::makeAsyncCullThread); private final ObjectArrayList> pendingTasks = new ObjectArrayList<>(); private SectionTree renderTree = null; private TaskSectionTree globalTaskTree = null; @@ -277,6 +273,12 @@ private SectionTree unpackTaskResults(boolean wait) { return latestTree; } + private static Thread makeAsyncCullThread(Runnable runnable) { + Thread thread = new Thread(runnable); + thread.setName("Sodium Async Cull Thread"); + return thread; + } + private void scheduleAsyncWork(Camera camera, Viewport viewport, boolean spectator) { // submit tasks of types that are applicable and not yet running AsyncRenderTask currentRunningTask = null; @@ -902,6 +904,24 @@ public int getVisibleChunkCount() { return sections; } + // TODO: this fixes very delayed tasks, but it still regresses on same-frame tasks that don't get to run in time because the frustum task collection task takes at least one (and usually only one) frame to run + // maybe intercept tasks that are scheduled in zero- or one-frame defer mode? + // collect and prioritize regardless of visibility if it's an important defer mode? + // TODO: vertical sorting seems to be broken? + private ChunkUpdateType upgradePendingUpdate(RenderSection section, ChunkUpdateType type) { + var current = section.getPendingUpdate(); + type = ChunkUpdateType.getPromotionUpdateType(current, type); + + section.setPendingUpdate(type, this.lastFrameAtTime); + + // if the section received a new task, mark in the task tree so an update can happen before a global cull task runs + if (this.globalTaskTree != null && type != null && current == null) { + this.globalTaskTree.markSectionTask(section); + } + + return type; + } + public void scheduleSort(long sectionPos, boolean isDirectTrigger) { RenderSection section = this.sectionByPosition.get(sectionPos); @@ -912,9 +932,8 @@ public void scheduleSort(long sectionPos, boolean isDirectTrigger) { || priorityMode == PriorityMode.NEARBY && this.shouldPrioritizeTask(section, NEARBY_SORT_DISTANCE)) { pendingUpdate = ChunkUpdateType.IMPORTANT_SORT; } - pendingUpdate = ChunkUpdateType.getPromotionUpdateType(section.getPendingUpdate(), pendingUpdate); - if (pendingUpdate != null) { - section.setPendingUpdate(pendingUpdate, this.lastFrameAtTime); + + if (this.upgradePendingUpdate(section, pendingUpdate) != null) { section.prepareTrigger(isDirectTrigger); } } @@ -936,10 +955,7 @@ public void scheduleRebuild(int x, int y, int z, boolean important) { pendingUpdate = ChunkUpdateType.REBUILD; } - pendingUpdate = ChunkUpdateType.getPromotionUpdateType(section.getPendingUpdate(), pendingUpdate); - if (pendingUpdate != null) { - section.setPendingUpdate(pendingUpdate, this.lastFrameAtTime); - + if (this.upgradePendingUpdate(section, pendingUpdate) != null) { this.markGraphDirty(); } } diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/TaskSectionTree.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/TaskSectionTree.java index 6ab711b692..708872b383 100644 --- a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/TaskSectionTree.java +++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/TaskSectionTree.java @@ -10,6 +10,7 @@ public class TaskSectionTree extends RayOcclusionSectionTree { private final TraversableForest taskTree; + private boolean taskTreeFinalized = false; public TaskSectionTree(Viewport viewport, float buildDistance, int frame, CullType cullType, Level level) { super(viewport, buildDistance, frame, cullType, level); @@ -17,20 +18,24 @@ public TaskSectionTree(Viewport viewport, float buildDistance, int frame, CullTy this.taskTree = TraversableForest.createTraversableForest(this.baseOffsetX, this.baseOffsetY, this.baseOffsetZ, buildDistance, level); } - @Override - protected void addPendingSection(RenderSection section, ChunkUpdateType type) { - super.addPendingSection(section, type); - + public void markSectionTask(RenderSection section) { this.taskTree.add(section.getChunkX(), section.getChunkY(), section.getChunkZ()); + this.taskTreeFinalized = false; } @Override - public void finalizeTrees() { - super.finalizeTrees(); - this.taskTree.calculateReduced(); + protected void addPendingSection(RenderSection section, ChunkUpdateType type) { + super.addPendingSection(section, type); + + this.markSectionTask(section); } public void traverseVisiblePendingTasks(VisibleSectionVisitor visitor, Viewport viewport, float distanceLimit) { + if (!this.taskTreeFinalized) { + this.taskTree.calculateReduced(); + this.taskTreeFinalized = true; + } + this.taskTree.traverse(visitor, viewport, distanceLimit); } } \ No newline at end of file diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/tree/BaseBiForest.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/tree/BaseBiForest.java index 87709af08c..ddbfe1ae05 100644 --- a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/tree/BaseBiForest.java +++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/tree/BaseBiForest.java @@ -24,14 +24,14 @@ protected T makeSecondaryTree() { @Override public void add(int x, int y, int z) { - if (!this.mainTree.add(x, y, z)) { - if (this.secondaryTree == null) { - this.secondaryTree = this.makeSecondaryTree(); - } - if (!this.secondaryTree.add(x, y, z)) { - throw new IllegalStateException("Failed to add section to trees"); - } + if (this.mainTree.add(x, y, z)) { + return; } + + if (this.secondaryTree == null) { + this.secondaryTree = this.makeSecondaryTree(); + } + this.secondaryTree.add(x, y, z); } @Override