10
10
import net .caffeinemc .mods .sodium .client .render .chunk .compile .BuilderTaskOutput ;
11
11
import net .caffeinemc .mods .sodium .client .render .chunk .compile .ChunkBuildOutput ;
12
12
import net .caffeinemc .mods .sodium .client .render .chunk .compile .ChunkSortOutput ;
13
- import net .caffeinemc .mods .sodium .client .render .chunk .compile .executor . ChunkBuilder ;
14
- import net .caffeinemc .mods .sodium .client .render .chunk .compile .executor . ChunkJobCollector ;
15
- import net .caffeinemc .mods .sodium .client .render .chunk .compile .executor . ChunkJobResult ;
16
- import net .caffeinemc .mods .sodium .client .render .chunk .compile .executor .JobEffortEstimator ;
13
+ import net .caffeinemc .mods .sodium .client .render .chunk .compile .estimation . JobDurationEstimator ;
14
+ import net .caffeinemc .mods .sodium .client .render .chunk .compile .estimation . MeshResultSize ;
15
+ import net .caffeinemc .mods .sodium .client .render .chunk .compile .estimation . MeshTaskSizeEstimator ;
16
+ import net .caffeinemc .mods .sodium .client .render .chunk .compile .executor .* ;
17
17
import net .caffeinemc .mods .sodium .client .render .chunk .compile .tasks .ChunkBuilderMeshingTask ;
18
18
import net .caffeinemc .mods .sodium .client .render .chunk .compile .tasks .ChunkBuilderSortingTask ;
19
19
import net .caffeinemc .mods .sodium .client .render .chunk .compile .tasks .ChunkBuilderTask ;
@@ -71,7 +71,8 @@ public class RenderSectionManager {
71
71
private final Long2ReferenceMap <RenderSection > sectionByPosition = new Long2ReferenceOpenHashMap <>();
72
72
73
73
private final ConcurrentLinkedDeque <ChunkJobResult <? extends BuilderTaskOutput >> buildResults = new ConcurrentLinkedDeque <>();
74
- private final JobEffortEstimator jobEffortEstimator = new JobEffortEstimator ();
74
+ private final JobDurationEstimator jobDurationEstimator = new JobDurationEstimator ();
75
+ private final MeshTaskSizeEstimator meshTaskSizeEstimator = new MeshTaskSizeEstimator ();
75
76
private ChunkJobCollector lastBlockingCollector ;
76
77
private long thisFrameBlockingTasks ;
77
78
private long nextFrameBlockingTasks ;
@@ -573,7 +574,10 @@ private boolean processChunkBuildResults(ArrayList<BuilderTaskOutput> results) {
573
574
TranslucentData oldData = result .render .getTranslucentData ();
574
575
if (result instanceof ChunkBuildOutput chunkBuildOutput ) {
575
576
this .updateSectionInfo (result .render , chunkBuildOutput .info );
576
- result .render .setLastMeshingTaskEffort (chunkBuildOutput .getEffort ());
577
+
578
+ var resultSize = chunkBuildOutput .getResultSize ();
579
+ result .render .setLastMeshResultSize (resultSize );
580
+ this .meshTaskSizeEstimator .addBatchEntry (MeshResultSize .forSection (result .render , resultSize ));
577
581
578
582
touchedSectionInfo = true ;
579
583
@@ -600,6 +604,8 @@ private boolean processChunkBuildResults(ArrayList<BuilderTaskOutput> results) {
600
604
result .render .setLastUploadFrame (result .submitTime );
601
605
}
602
606
607
+ this .meshTaskSizeEstimator .flushNewData ();
608
+
603
609
return touchedSectionInfo ;
604
610
}
605
611
@@ -642,11 +648,11 @@ private ArrayList<BuilderTaskOutput> collectChunkBuildResults() {
642
648
results .add (result .unwrap ());
643
649
var jobEffort = result .getJobEffort ();
644
650
if (jobEffort != null ) {
645
- this .jobEffortEstimator . addJobEffort (jobEffort );
651
+ this .jobDurationEstimator . addBatchEntry (jobEffort );
646
652
}
647
653
}
648
654
649
- this .jobEffortEstimator .flushNewData ();
655
+ this .jobDurationEstimator .flushNewData ();
650
656
651
657
return results ;
652
658
}
@@ -670,21 +676,22 @@ public void updateChunks(boolean updateImmediately) {
670
676
if (updateImmediately ) {
671
677
// for a perfect frame where everything is finished use the last frame's blocking collector
672
678
// and add all tasks to it so that they're waited on
673
- this .submitSectionTasks (thisFrameBlockingCollector , thisFrameBlockingCollector , thisFrameBlockingCollector );
679
+ this .submitSectionTasks (Long . MAX_VALUE , thisFrameBlockingCollector , thisFrameBlockingCollector , thisFrameBlockingCollector );
674
680
675
681
this .thisFrameBlockingTasks = thisFrameBlockingCollector .getSubmittedTaskCount ();
676
682
thisFrameBlockingCollector .awaitCompletion (this .builder );
677
683
} else {
678
684
var nextFrameBlockingCollector = new ChunkJobCollector (this .buildResults ::add );
679
685
var remainingDuration = this .builder .getTotalRemainingDuration (this .averageFrameDuration );
686
+ var remainingUploadSize = this .regions .getStagingBuffer ().getUploadSizeLimit (this .averageFrameDuration );
680
687
var deferredCollector = new ChunkJobCollector (remainingDuration , this .buildResults ::add );
681
688
682
689
// if zero frame delay is allowed, submit important sorts with the current frame blocking collector.
683
690
// otherwise submit with the collector that the next frame is blocking on.
684
691
if (SodiumClientMod .options ().performance .getSortBehavior ().getDeferMode () == DeferMode .ZERO_FRAMES ) {
685
- this .submitSectionTasks (thisFrameBlockingCollector , nextFrameBlockingCollector , deferredCollector );
692
+ this .submitSectionTasks (remainingUploadSize , thisFrameBlockingCollector , nextFrameBlockingCollector , deferredCollector );
686
693
} else {
687
- this .submitSectionTasks (nextFrameBlockingCollector , nextFrameBlockingCollector , deferredCollector );
694
+ this .submitSectionTasks (remainingUploadSize , nextFrameBlockingCollector , nextFrameBlockingCollector , deferredCollector );
688
695
}
689
696
690
697
this .thisFrameBlockingTasks = thisFrameBlockingCollector .getSubmittedTaskCount ();
@@ -701,6 +708,7 @@ public void updateChunks(boolean updateImmediately) {
701
708
}
702
709
703
710
private void submitSectionTasks (
711
+ long remainingUploadSize ,
704
712
ChunkJobCollector importantCollector ,
705
713
ChunkJobCollector semiImportantCollector ,
706
714
ChunkJobCollector deferredCollector ) {
@@ -711,11 +719,15 @@ private void submitSectionTasks(
711
719
case ALWAYS -> deferredCollector ;
712
720
};
713
721
714
- submitSectionTasks (collector , deferMode );
722
+ // don't limit on size for zero frame defer (needs to be done, no matter the limit)
723
+ remainingUploadSize = submitSectionTasks (remainingUploadSize , deferMode != DeferMode .ZERO_FRAMES , collector , deferMode );
724
+ if (remainingUploadSize <= 0 ) {
725
+ break ;
726
+ }
715
727
}
716
728
}
717
729
718
- private void submitSectionTasks (ChunkJobCollector collector , DeferMode deferMode ) {
730
+ private long submitSectionTasks (long remainingUploadSize , boolean limitOnSize , ChunkJobCollector collector , DeferMode deferMode ) {
719
731
LongHeapPriorityQueue frustumQueue = null ;
720
732
LongHeapPriorityQueue globalQueue = null ;
721
733
float frustumPriorityBias = 0 ;
@@ -743,7 +755,8 @@ private void submitSectionTasks(ChunkJobCollector collector, DeferMode deferMode
743
755
long frustumItem = 0 ;
744
756
long globalItem = 0 ;
745
757
746
- while ((!frustumQueue .isEmpty () || !globalQueue .isEmpty ()) && collector .hasBudgetRemaining ()) {
758
+ while ((!frustumQueue .isEmpty () || !globalQueue .isEmpty ()) &&
759
+ collector .hasBudgetRemaining () && (!limitOnSize || remainingUploadSize > 0 )) {
747
760
// get the first item from the non-empty queues and see which one has higher priority.
748
761
// if the priority is not infinity, then the item priority was fetched the last iteration and doesn't need updating.
749
762
if (!frustumQueue .isEmpty () && Float .isInfinite (frustumPriority )) {
@@ -780,18 +793,17 @@ private void submitSectionTasks(ChunkJobCollector collector, DeferMode deferMode
780
793
continue ;
781
794
}
782
795
783
- int frame = this .frame ;
784
796
ChunkBuilderTask <? extends BuilderTaskOutput > task ;
785
797
if (type == ChunkUpdateType .SORT || type == ChunkUpdateType .IMPORTANT_SORT ) {
786
- task = this .createSortTask (section , frame );
798
+ task = this .createSortTask (section , this . frame );
787
799
788
800
if (task == null ) {
789
801
// when a sort task is null it means the render section has no dynamic data and
790
802
// doesn't need to be sorted. Nothing needs to be done.
791
803
continue ;
792
804
}
793
805
} else {
794
- task = this .createRebuildTask (section , frame );
806
+ task = this .createRebuildTask (section , this . frame );
795
807
796
808
if (task == null ) {
797
809
// if the section is empty or doesn't exist submit this null-task to set the
@@ -804,7 +816,7 @@ private void submitSectionTasks(ChunkJobCollector collector, DeferMode deferMode
804
816
// rebuild that must have happened in the meantime includes new non-dynamic
805
817
// index data.
806
818
var result = ChunkJobResult .successfully (new ChunkBuildOutput (
807
- section , frame , NoData .forEmptySection (section .getPosition ()),
819
+ section , this . frame , NoData .forEmptySection (section .getPosition ()),
808
820
BuiltSectionInfo .EMPTY , Collections .emptyMap ()));
809
821
this .buildResults .add (result );
810
822
@@ -815,13 +827,16 @@ private void submitSectionTasks(ChunkJobCollector collector, DeferMode deferMode
815
827
if (task != null ) {
816
828
var job = this .builder .scheduleTask (task , type .isImportant (), collector ::onJobFinished );
817
829
collector .addSubmittedJob (job );
830
+ remainingUploadSize -= job .getEstimatedSize ();
818
831
819
832
section .setTaskCancellationToken (job );
820
833
}
821
834
822
- section .setLastSubmittedFrame (frame );
835
+ section .setLastSubmittedFrame (this . frame );
823
836
section .clearPendingUpdate ();
824
837
}
838
+
839
+ return remainingUploadSize ;
825
840
}
826
841
827
842
public @ Nullable ChunkBuilderMeshingTask createRebuildTask (RenderSection render , int frame ) {
@@ -832,14 +847,14 @@ private void submitSectionTasks(ChunkJobCollector collector, DeferMode deferMode
832
847
}
833
848
834
849
var task = new ChunkBuilderMeshingTask (render , frame , this .cameraPosition , context );
835
- task .estimateDurationWith (this .jobEffortEstimator );
850
+ task .calculateEstimations (this .jobDurationEstimator , this . meshTaskSizeEstimator );
836
851
return task ;
837
852
}
838
853
839
854
public ChunkBuilderSortingTask createSortTask (RenderSection render , int frame ) {
840
855
var task = ChunkBuilderSortingTask .createTask (render , frame , this .cameraPosition );
841
856
if (task != null ) {
842
- task .estimateDurationWith (this .jobEffortEstimator );
857
+ task .calculateEstimations (this .jobDurationEstimator , this . meshTaskSizeEstimator );
843
858
}
844
859
return task ;
845
860
}
0 commit comments