Skip to content

Commit

Permalink
fix some issues with very delayed section sorting. There are still ot…
Browse files Browse the repository at this point in the history
…her issues with (at least vertical) sorting though and even important zero-frame blocking tasks are not scheduled within the same frame
  • Loading branch information
douira committed Dec 2, 2024
1 parent f969cbb commit ecdd040
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<AsyncRenderTask<?>> pendingTasks = new ObjectArrayList<>();
private SectionTree renderTree = null;
private TaskSectionTree globalTaskTree = null;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand All @@ -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);
}
}
Expand All @@ -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();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,32 @@

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);

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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit ecdd040

Please sign in to comment.