wip(standalone): GPU step 22 -- startup multi-batch pump, pool before handoff: cached 1.12-1.20 s
Per-batch GPU timeline (submit, timestamps, query, consume). Startup Draws submit
several ready batches per pump (80 ms startup budget, 16 ms per batch); the output
pool is reserved before the warm-up-pending deferral.
My runs outside the sandbox (Step22.exe, marker removed first, interleaved):
CPU 1.295 / 1.314 / 1.284 / 1.342 s
GPU cached (marker match, -Timeline): 1.197 / 1.121 / 1.133 s
(1,124 / 1,380 / 1,415 GPU tiles; output pool at 655-680 ms in all three)
GPU marker miss: 1.446 (-Timeline), 1.447, 1.312 s (no -Timeline). The 1.447 run's
shape compile ended at 776 ms vs 634-643 ms in its neighbours, so this is
startup variance, not a clear regression; to be watched.
Known tradeoff: startup pumps can stall the main thread 65-108 ms (submit calls run
past the budget); fine before the first view, to check in an interactive viewer.
Audits: hashes w1/w8, walk 5,642/5,642, near 960 / far 1,114 0 diffs vs CPU and
WARP, thin 353, survival ~6.2 GiB, ten captures as step 18.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
38f6009200
commit
052b6de354
7 files changed
+274
-43
No files matched your search
@@ -1393,10 +1393,13 @@ namespace
|
||||
uint32 ResidentCount=0;
|
||||
std::vector<FVoxelTileKey> Keys;
|
||||
uint64 TimestampFrequency=0;
|
||||
uint64 GpuStartTimestamp=0,GpuEndTimestamp=0;
|
||||
double GpuDispatchMs=0.0;
|
||||
std::chrono::steady_clock::time_point PreparedAt{};
|
||||
std::chrono::steady_clock::time_point SubmitStartedAt{};
|
||||
std::chrono::steady_clock::time_point SubmittedAt{};
|
||||
std::chrono::steady_clock::time_point CompletedAt{};
|
||||
std::chrono::steady_clock::time_point ConsumedAt{};
|
||||
bool bGpuComplete=false,bTimingResolved=false;
|
||||
};
|
||||
|
||||
@@ -1559,6 +1562,7 @@ namespace
|
||||
std::atomic<uint64> GpuFarPreparationGeneration{0};
|
||||
std::atomic<bool> bGpuFarPreparationFinished{false};
|
||||
bool bGpuFarPreparationStarted=false,bGpuFarInputsFinalized=false;
|
||||
bool bGpuFarPreparationDeferredReported=false;
|
||||
bool bGpuFarFirstPreparedInputReported=false;
|
||||
bool bGpuWarmupCompleted=false,bGpuFarTimelineEnabled=false;
|
||||
bool bGpuWarmupRoutePending=false;
|
||||
@@ -1605,6 +1609,7 @@ namespace
|
||||
uint64 GpuFarSubmissionBatches=0;
|
||||
uint32 GpuFarMaxTilesPerSubmissionBatch=0;
|
||||
uint32 GpuFarOutputCapacitySlots=0,GpuFarNextOutputSlot=0;
|
||||
uint32 GpuFarOutputPoolReservedSlots=0;
|
||||
std::vector<uint32> GpuFarFreeOutputSlots;
|
||||
std::unordered_map<FVoxelTileKey,VoxelForgeCore::FarFieldTileInput,FStandaloneTileKeyHash> GpuFarPreparedInputs;
|
||||
std::unordered_map<FVoxelTileKey,std::string,FStandaloneTileKeyHash> GpuFarPreparationErrors;
|
||||
@@ -1756,6 +1761,7 @@ namespace
|
||||
GpuFarCandidateTiles.clear();GpuFarBaseCpuFallbackTiles.clear();
|
||||
GpuFarCpuFallbackTiles.clear();GpuFarNeedPreparation.clear();
|
||||
bGpuFarPreparationStarted=false;bGpuFarInputsFinalized=false;
|
||||
bGpuFarPreparationDeferredReported=false;
|
||||
bGpuFarPreparationFinished.store(false,std::memory_order_relaxed);
|
||||
bGpuWarmupRoutePending=false;
|
||||
GpuFarWarmupCpuClaimedTiles=0;GpuFarWarmupGpuTakeoverTiles=0;
|
||||
@@ -1778,6 +1784,7 @@ namespace
|
||||
GpuSkirtDrawAuditSumIndices=GpuSkirtDrawAuditMaxIndices=0;
|
||||
GpuFarPoolReserveMs=0.0;
|
||||
GpuFarSubmissionBatches=0;GpuFarMaxTilesPerSubmissionBatch=0;
|
||||
GpuFarOutputPoolReservedSlots=0;
|
||||
DirtyBatchSet.clear();DesiredTiles.clear();DesiredTileSet.clear();CrossingWork.clear();
|
||||
DeferredLeaverTiles.clear();
|
||||
for(int32 I=0;I<=MaxLevels;++I)
|
||||
@@ -2668,7 +2675,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
{
|
||||
if(Tile.CompletedAt.time_since_epoch().count()!=0)return;
|
||||
Tile.CompletedAt=std::chrono::steady_clock::now();
|
||||
if(!bGpuFarTimelineEnabled)return;
|
||||
if(!bGpuFarTimelineEnabled||BatchIndex!=UINT32_MAX)return;
|
||||
std::printf("[GpuTileTimeline] event=completed key=(%d,%d,%d,lod%d) batch=%u at_ms=%.3f frame=%llu submitted_ms=%.3f\n",
|
||||
Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level,BatchIndex,
|
||||
ColdTimelineMilliseconds(Tile.CompletedAt),
|
||||
@@ -2685,7 +2692,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
if(Tile.bColdTimelineResidentReported)return;
|
||||
Tile.bColdTimelineResidentReported=true;
|
||||
const auto ResidentAt=std::chrono::steady_clock::now();
|
||||
if(bGpuFarTimelineEnabled)
|
||||
if(bGpuFarTimelineEnabled&&Tile.BatchIndex==UINT32_MAX)
|
||||
std::printf("[GpuTileTimeline] event=resident key=(%d,%d,%d,lod%d) batch=%u at_ms=%.3f frame=%llu submitted_ms=%.3f completed_ms=%.3f\n",
|
||||
Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level,Tile.BatchIndex,
|
||||
ColdTimelineMilliseconds(ResidentAt),
|
||||
@@ -2696,10 +2703,69 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
FGpuFarBatch& Batch=GpuFarBatches[Tile.BatchIndex];
|
||||
++Batch.ResidentCount;
|
||||
if(bGpuFarTimelineEnabled&&Batch.ResidentCount==Batch.TileCount)
|
||||
{
|
||||
Batch.ConsumedAt=ResidentAt;
|
||||
std::printf("[GpuBatchTimeline] event=resident batch=%u at_ms=%.3f frame=%llu tile_count=%u submitted_ms=%.3f completed_ms=%.3f\n",
|
||||
Tile.BatchIndex,ColdTimelineMilliseconds(ResidentAt),
|
||||
static_cast<unsigned long long>(ColdTimelineFrame()),Batch.TileCount,
|
||||
ColdTimelineMilliseconds(Batch.SubmittedAt),ColdTimelineMilliseconds(Batch.CompletedAt));
|
||||
std::printf("[GpuBatchTimeline] event=consumed batch=%u at_ms=%.3f frame=%llu tile_count=%u submit_to_gpu_complete_ms=%.3f gpu_complete_to_consumed_ms=%.3f output=direct_gpu_buffers\n",
|
||||
Tile.BatchIndex,ColdTimelineMilliseconds(ResidentAt),
|
||||
static_cast<unsigned long long>(ColdTimelineFrame()),Batch.TileCount,
|
||||
ColdTimelineMilliseconds(Batch.CompletedAt)-ColdTimelineMilliseconds(Batch.SubmittedAt),
|
||||
ColdTimelineMilliseconds(ResidentAt)-ColdTimelineMilliseconds(Batch.CompletedAt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReportGpuBatchTimelineSummary()
|
||||
{
|
||||
if(!bGpuFarTimelineEnabled)return;
|
||||
uint64 FirstGpuStart=0,CommonFrequency=0;
|
||||
for(const FGpuFarBatch& Batch:GpuFarBatches)
|
||||
{
|
||||
if(Batch.bTimingResolved&&Batch.TimestampFrequency&&Batch.GpuStartTimestamp)
|
||||
{
|
||||
FirstGpuStart=Batch.GpuStartTimestamp;
|
||||
CommonFrequency=Batch.TimestampFrequency;
|
||||
break;
|
||||
}
|
||||
}
|
||||
uint64 PreviousGpuEnd=0,PreviousFrequency=0;
|
||||
for(std::size_t I=0;I<GpuFarBatches.size();++I)
|
||||
{
|
||||
const FGpuFarBatch& Batch=GpuFarBatches[I];
|
||||
const auto AtMs=[this](const std::chrono::steady_clock::time_point& At)
|
||||
{
|
||||
return At.time_since_epoch().count()!=0
|
||||
?ColdTimelineMilliseconds(At):-1.0;
|
||||
};
|
||||
double GpuStartFromFirstMs=-1.0,GpuEndFromFirstMs=-1.0,GpuGapBeforeMs=-1.0;
|
||||
if(Batch.bTimingResolved&&Batch.TimestampFrequency&&Batch.GpuStartTimestamp
|
||||
&&CommonFrequency==Batch.TimestampFrequency&&FirstGpuStart)
|
||||
{
|
||||
GpuStartFromFirstMs=(static_cast<double>(Batch.GpuStartTimestamp)
|
||||
-static_cast<double>(FirstGpuStart))*1000.0/Batch.TimestampFrequency;
|
||||
GpuEndFromFirstMs=(static_cast<double>(Batch.GpuEndTimestamp)
|
||||
-static_cast<double>(FirstGpuStart))*1000.0/Batch.TimestampFrequency;
|
||||
if(PreviousGpuEnd&&PreviousFrequency==Batch.TimestampFrequency)
|
||||
GpuGapBeforeMs=(static_cast<double>(Batch.GpuStartTimestamp)
|
||||
-static_cast<double>(PreviousGpuEnd))*1000.0/Batch.TimestampFrequency;
|
||||
}
|
||||
std::printf("[GpuBatchTimeline] event=summary batch=%zu tiles=%u cpu_batch_ready_ms=%.3f cpu_submit_begin_ms=%.3f cpu_submit_end_ms=%.3f gpu_start_tick=%llu gpu_end_tick=%llu timestamp_frequency_hz=%llu gpu_start_from_first_ms=%.3f gpu_end_from_first_ms=%.3f gpu_gap_from_previous_end_ms=%.3f gpu_busy_ms=%.3f completion_observed_ms=%.3f consumed_ms=%.3f submit_to_completion_observed_ms=%.3f completion_to_consumed_ms=%.3f timing_resolved=%s\n",
|
||||
I,Batch.TileCount,AtMs(Batch.PreparedAt),AtMs(Batch.SubmitStartedAt),
|
||||
AtMs(Batch.SubmittedAt),static_cast<unsigned long long>(Batch.GpuStartTimestamp),
|
||||
static_cast<unsigned long long>(Batch.GpuEndTimestamp),
|
||||
static_cast<unsigned long long>(Batch.TimestampFrequency),GpuStartFromFirstMs,
|
||||
GpuEndFromFirstMs,GpuGapBeforeMs,Batch.GpuDispatchMs,AtMs(Batch.CompletedAt),
|
||||
AtMs(Batch.ConsumedAt),Batch.CompletedAt.time_since_epoch().count()!=0
|
||||
?AtMs(Batch.CompletedAt)-AtMs(Batch.SubmittedAt):-1.0,
|
||||
Batch.ConsumedAt.time_since_epoch().count()!=0
|
||||
&&Batch.CompletedAt.time_since_epoch().count()!=0
|
||||
?AtMs(Batch.ConsumedAt)-AtMs(Batch.CompletedAt):-1.0,
|
||||
Batch.bTimingResolved?"yes":"no");
|
||||
if(Batch.bTimingResolved&&Batch.TimestampFrequency&&Batch.GpuEndTimestamp)
|
||||
{PreviousGpuEnd=Batch.GpuEndTimestamp;PreviousFrequency=Batch.TimestampFrequency;}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2741,13 +2807,16 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
{
|
||||
BatchTileIt->second.bGpuComplete=true;
|
||||
ReportGpuTileCompletion(BatchKey,BatchTileIt->second,Tile.BatchIndex);
|
||||
RecordGpuCrossingTileReady(BatchKey);
|
||||
ReportGpuTileResident(BatchKey,BatchTileIt->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(Batch.bGpuComplete&&!Batch.bTimingResolved)
|
||||
{
|
||||
if(VoxelForgeGpuFarViewer::ResolveGpuTiming(Context,Batch.TimingQueries,
|
||||
Batch.GpuDispatchMs,&Batch.TimestampFrequency))
|
||||
Batch.GpuDispatchMs,&Batch.TimestampFrequency,
|
||||
&Batch.GpuStartTimestamp,&Batch.GpuEndTimestamp))
|
||||
{
|
||||
Batch.bTimingResolved=true;
|
||||
GpuFarSubmissionSpanMs+=Batch.GpuDispatchMs;
|
||||
@@ -2933,6 +3002,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
GpuFarCandidateTiles.clear();GpuFarBaseCpuFallbackTiles.clear();
|
||||
GpuFarCpuFallbackTiles.clear();GpuFarNeedPreparation.clear();
|
||||
bGpuFarPreparationStarted=false;bGpuFarInputsFinalized=false;
|
||||
bGpuFarPreparationDeferredReported=false;
|
||||
bGpuFarFirstPreparedInputReported=false;
|
||||
bGpuFarPreparationFinished.store(false,std::memory_order_relaxed);
|
||||
bGpuWarmupRoutePending=false;
|
||||
@@ -3006,6 +3076,11 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
bGpuWarmupRoutePending=bGpuFarShaderPrewarm&&!bGpuFarAuditEnabled
|
||||
&&!bGpuWarmupCompleted&&!bGpuFarWarmupBeforeWorkers
|
||||
&&!GpuFarCandidateTiles.empty();
|
||||
if(bGpuFarTimelineEnabled)
|
||||
std::printf("[ColdTimeline] event=gpu_output_pool_candidates at_ms=%.3f slots=%u candidates=%zu warmup_handoff_pending=%s\n",
|
||||
ColdTimelineMilliseconds(std::chrono::steady_clock::now()),
|
||||
GpuFarOutputCapacitySlots,GpuFarCandidateTiles.size(),
|
||||
bGpuWarmupRoutePending?"yes":"no");
|
||||
if(bGpuWarmupRoutePending)
|
||||
{
|
||||
GpuFarCpuFallbackTiles.reserve(GpuFarCpuFallbackTiles.size()+GpuFarCandidateTiles.size());
|
||||
@@ -3050,40 +3125,53 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
void StartGpuFarPreparation()
|
||||
{
|
||||
if(!bGpuFarEnabled||!ShapeWorld||!ShapeWorld->hasFarWorld()||bGpuFarPreparationStarted)return;
|
||||
if(bGpuWarmupDeferredUntilFirstView&&!bGpuWarmupDeferredStarted)return;
|
||||
if(GpuFarCandidateTiles.empty())
|
||||
{
|
||||
bGpuFarPreparationStarted=true;
|
||||
bGpuFarInputsFinalized=true;
|
||||
bGpuFarPreparationFinished.store(true,std::memory_order_relaxed);
|
||||
return;
|
||||
}
|
||||
if(GpuFarOutputPoolReservedSlots<GpuFarOutputCapacitySlots)
|
||||
{
|
||||
const auto ReserveStart=std::chrono::steady_clock::now();
|
||||
std::printf("[ColdTimeline] stage=gpu_output_pool begin_ms=%.3f slots=%u reason=reserve_before_warmup_handoff\n",
|
||||
ColdTimelineMilliseconds(ReserveStart),GpuFarOutputCapacitySlots);
|
||||
std::string PoolError;
|
||||
if(!VoxelForgeGpuFarViewer::ReserveFarOutputPool(Device,Context,GpuFarShaderPath,
|
||||
GpuFarOutputCapacitySlots,static_cast<uint32>(World->CoarseTileCells),PoolError))
|
||||
{
|
||||
std::fprintf(stderr,"[GpuFarPoolError] %s\n",PoolError.c_str());
|
||||
bGpuFarEnabled=false;bGpuFarPreparationStarted=true;
|
||||
GpuFarOutputCapacitySlots=0;GpuFarOutputPoolReservedSlots=0;
|
||||
for(auto& Pair:GpuFarTiles)ReleaseGpuFarTile(Pair.second);
|
||||
GpuFarTiles.clear();GpuFarCandidateTiles.clear();GpuFarQueue.clear();GpuFarQueued.clear();
|
||||
GpuFarNeedPreparation.clear();GpuFarEligibleTiles.clear();
|
||||
AddGpuFarCpuFallbackTiles(DesiredTiles);
|
||||
bGpuFarInputsFinalized=true;
|
||||
bGpuFarPreparationFinished.store(true,std::memory_order_relaxed);
|
||||
return;
|
||||
}
|
||||
const double ReserveMs=std::chrono::duration<double,std::milli>(
|
||||
std::chrono::steady_clock::now()-ReserveStart).count();
|
||||
GpuFarPoolReserveMs+=ReserveMs;
|
||||
GpuFarOutputPoolReservedSlots=GpuFarOutputCapacitySlots;
|
||||
std::printf("[ColdTimeline] stage=gpu_output_pool end_ms=%.3f duration_ms=%.3f reserved_slots=%u\n",
|
||||
ColdTimelineMilliseconds(std::chrono::steady_clock::now()),ReserveMs,
|
||||
GpuFarOutputPoolReservedSlots);
|
||||
}
|
||||
if(bGpuWarmupRoutePending&&!bGpuWarmupCompleted)
|
||||
{
|
||||
std::printf("[GpuFarPrepDeferred] reason=shader_warmup_cpu_tiles_own_candidates tiles=%zu\n",
|
||||
GpuFarCandidateTiles.size());
|
||||
if(!bGpuFarPreparationDeferredReported)
|
||||
{
|
||||
bGpuFarPreparationDeferredReported=true;
|
||||
std::printf("[GpuFarPrepDeferred] reason=shader_warmup_cpu_tiles_own_candidates tiles=%zu output_pool_reserved_slots=%u\n",
|
||||
GpuFarCandidateTiles.size(),GpuFarOutputPoolReservedSlots);
|
||||
}
|
||||
return;
|
||||
}
|
||||
bGpuFarPreparationStarted=true;
|
||||
if(GpuFarCandidateTiles.empty())
|
||||
{
|
||||
bGpuFarInputsFinalized=true;
|
||||
bGpuFarPreparationFinished.store(true,std::memory_order_relaxed);
|
||||
return;
|
||||
}
|
||||
const auto ReserveStart=std::chrono::steady_clock::now();
|
||||
std::printf("[ColdTimeline] stage=gpu_output_pool begin_ms=%.3f slots=%u\n",
|
||||
ColdTimelineMilliseconds(ReserveStart),GpuFarOutputCapacitySlots);
|
||||
std::string PoolError;
|
||||
if(!VoxelForgeGpuFarViewer::ReserveFarOutputPool(Device,Context,GpuFarShaderPath,
|
||||
GpuFarOutputCapacitySlots,static_cast<uint32>(World->CoarseTileCells),PoolError))
|
||||
{
|
||||
std::fprintf(stderr,"[GpuFarPoolError] %s\n",PoolError.c_str());
|
||||
bGpuFarEnabled=false;GpuFarOutputCapacitySlots=0;
|
||||
for(auto& Pair:GpuFarTiles)ReleaseGpuFarTile(Pair.second);
|
||||
GpuFarTiles.clear();GpuFarCandidateTiles.clear();GpuFarQueue.clear();GpuFarQueued.clear();
|
||||
GpuFarNeedPreparation.clear();GpuFarEligibleTiles.clear();
|
||||
AddGpuFarCpuFallbackTiles(DesiredTiles);
|
||||
bGpuFarInputsFinalized=true;
|
||||
bGpuFarPreparationFinished.store(true,std::memory_order_relaxed);
|
||||
return;
|
||||
}
|
||||
GpuFarPoolReserveMs+=std::chrono::duration<double,std::milli>(
|
||||
std::chrono::steady_clock::now()-ReserveStart).count();
|
||||
std::printf("[ColdTimeline] stage=gpu_output_pool end_ms=%.3f duration_ms=%.3f\n",
|
||||
ColdTimelineMilliseconds(std::chrono::steady_clock::now()),GpuFarPoolReserveMs);
|
||||
const auto PoolEnd=std::chrono::steady_clock::now();
|
||||
const auto MemorySampleStart=std::chrono::steady_clock::now();
|
||||
SampleGpuFarMemory();
|
||||
@@ -3317,7 +3405,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PumpGpuFarGeneration()
|
||||
void PumpGpuFarGeneration(double MaxPumpBudgetMilliseconds=8.0)
|
||||
{
|
||||
if(!bGpuFarEnabled||!ShapeWorld||!ShapeWorld->hasFarWorld()||!Device||!Context)return;
|
||||
if(bGpuWarmupDeferredUntilFirstView&&!bGpuWarmupDeferredStarted)
|
||||
@@ -3341,6 +3429,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
std::string PipelineError;
|
||||
if(!EnsureGpuFarPipeline(PipelineError))
|
||||
{bGpuFarEnabled=false;AddGpuFarCpuFallbackTiles(DesiredTiles);return;}
|
||||
StartGpuFarPreparation();
|
||||
if(!CompleteGpuShaderWarmupAndRoute())return;
|
||||
StartGpuFarPreparation();
|
||||
if(!bGpuFarEnabled||!FinalizeGpuFarPreparation()||GpuFarQueue.empty())return;
|
||||
@@ -3348,18 +3437,18 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
&&!bDisableGpuColdStartDrain&&bGpuFarWarmupBeforeWorkers;
|
||||
constexpr std::size_t StartupFirstGpuBatchTarget=32;
|
||||
constexpr std::size_t StartupGpuBatchTarget=256;
|
||||
constexpr double StartupGpuPumpBudgetMilliseconds=8.0;
|
||||
constexpr double StartupGpuPumpBudgetMilliseconds=16.0;
|
||||
const bool bWaitForStreamingGpuBatch=!bColdDrainBeforeWholeView
|
||||
&&!bGpuFarAuditEnabled&&!bInitialClipmapReported;
|
||||
const std::size_t GpuPumpTileLimit=bWaitForStreamingGpuBatch
|
||||
?(GpuFarSubmissionBatches==0?StartupFirstGpuBatchTarget:StartupGpuBatchTarget):32;
|
||||
const double GpuPumpBudgetMilliseconds=bWaitForStreamingGpuBatch
|
||||
?StartupGpuPumpBudgetMilliseconds:4.0;
|
||||
const double GpuPumpBudgetMilliseconds=std::min(MaxPumpBudgetMilliseconds,
|
||||
bWaitForStreamingGpuBatch?StartupGpuPumpBudgetMilliseconds:4.0);
|
||||
if(bWaitForStreamingGpuBatch
|
||||
&&!bGpuFarPreparationFinished.load(std::memory_order_acquire)
|
||||
&&GpuFarQueue.size()<StartupFirstGpuBatchTarget)return;
|
||||
if(bWaitForStreamingGpuBatch&&GpuFarSubmissionBatches==0)
|
||||
std::printf("[GpuFarStreamingPolicy] first_batch_tiles=%zu start_threshold=%zu later_batch_limit=%zu pump_budget_ms=%.1f order=lod_then_camera_distance\n",
|
||||
std::printf("[GpuFarStreamingPolicy] first_batch_tiles=%zu start_threshold=%zu later_batch_limit=%zu per_draw_budget_ms=80.0 per_batch_build_budget_ms=%.1f submit_batches_per_draw=until_budget_or_input_starvation order=lod_then_camera_distance\n",
|
||||
GpuFarQueue.size(),StartupFirstGpuBatchTarget,StartupGpuBatchTarget,
|
||||
StartupGpuPumpBudgetMilliseconds);
|
||||
const auto PumpStart=std::chrono::steady_clock::now();
|
||||
@@ -3911,6 +4000,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
BatchIndex,ColdTimelineMilliseconds(Batch.PreparedAt),
|
||||
static_cast<unsigned long long>(ColdTimelineFrame()),Batch.TileCount);
|
||||
std::string BatchError;
|
||||
Batch.SubmitStartedAt=std::chrono::steady_clock::now();
|
||||
if(!VoxelForgeGpuFarViewer::SubmitFarTileBatch(Device,Context,GpuFarShaderPath,
|
||||
&Batch.CompletionEvent,&Batch.TimingQueries,BatchError))
|
||||
{
|
||||
@@ -3932,16 +4022,23 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
{
|
||||
It->second.BatchIndex=BatchIndex;
|
||||
It->second.SubmittedAt=Batch.SubmittedAt;
|
||||
if(bGpuFarTimelineEnabled)std::printf("[GpuTileTimeline] event=submitted key=(%d,%d,%d,lod%d) batch=%u at_ms=%.3f frame=%llu prepared_ms=%.3f\n",
|
||||
if(bGpuFarTimelineEnabled&&!bDeferredBatch)std::printf("[GpuTileTimeline] event=submitted key=(%d,%d,%d,lod%d) batch=%u at_ms=%.3f frame=%llu prepared_ms=%.3f\n",
|
||||
Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level,BatchIndex,
|
||||
ColdTimelineMilliseconds(Batch.SubmittedAt),
|
||||
static_cast<unsigned long long>(ColdTimelineFrame()),
|
||||
ColdTimelineMilliseconds(It->second.PreparedAt));
|
||||
}
|
||||
}
|
||||
if(bGpuFarTimelineEnabled)std::printf("[GpuBatchTimeline] event=submitted batch=%u at_ms=%.3f frame=%llu tile_count=%u\n",
|
||||
BatchIndex,ColdTimelineMilliseconds(Batch.SubmittedAt),
|
||||
if(bGpuFarTimelineEnabled)std::printf("[GpuBatchTimeline] event=cpu_submit batch=%u begin_ms=%.3f end_ms=%.3f cpu_submit_ms=%.3f frame=%llu tile_count=%u\n",
|
||||
BatchIndex,ColdTimelineMilliseconds(Batch.SubmitStartedAt),
|
||||
ColdTimelineMilliseconds(Batch.SubmittedAt),
|
||||
std::chrono::duration<double,std::milli>(
|
||||
Batch.SubmittedAt-Batch.SubmitStartedAt).count(),
|
||||
static_cast<unsigned long long>(ColdTimelineFrame()),Batch.TileCount);
|
||||
if(bGpuFarTimelineEnabled)std::printf("[GpuBatchTimeline] event=submitted batch=%u at_ms=%.3f frame=%llu tile_count=%u cpu_submit_begin_ms=%.3f\n",
|
||||
BatchIndex,ColdTimelineMilliseconds(Batch.SubmittedAt),
|
||||
static_cast<unsigned long long>(ColdTimelineFrame()),Batch.TileCount,
|
||||
ColdTimelineMilliseconds(Batch.SubmitStartedAt));
|
||||
++GpuFarSubmissionBatches;
|
||||
GpuFarMaxTilesPerSubmissionBatch=std::max<uint32>(GpuFarMaxTilesPerSubmissionBatch,
|
||||
static_cast<uint32>(Built));
|
||||
@@ -4699,6 +4796,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
std::printf("[GpuFarMemory] dxgi_local_sampled_peak_mb=%.1f dxgi_local_budget_mb=%.1f\n",
|
||||
GpuFarLocalMemoryPeakBytes/(1024.0*1024.0),
|
||||
GpuFarLocalMemoryBudgetBytes/(1024.0*1024.0));
|
||||
ReportGpuBatchTimelineSummary();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4784,7 +4882,26 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
const auto CpuPumpEnd=std::chrono::steady_clock::now();
|
||||
const bool bDeferGpuUntilCpuFrame=bGpuFarEnabled&&bPresentCpuFrameBeforeGpu
|
||||
&&!bCpuReadyFramePresentedBeforeGpu;
|
||||
if(!bDeferGpuUntilCpuFrame)PumpGpuFarGeneration();
|
||||
if(!bDeferGpuUntilCpuFrame)
|
||||
{
|
||||
// Startup holds the last CPU front buffer while the GPU route takes over.
|
||||
// Allow several ready batches to be submitted in one draw before resuming it.
|
||||
constexpr double StartupGpuPumpFrameBudgetMilliseconds=80.0;
|
||||
const auto GpuPumpFrameStart=std::chrono::steady_clock::now();
|
||||
uint64 PreviousSubmissionCount=GpuFarSubmissionBatches;
|
||||
for(;;)
|
||||
{
|
||||
const double ElapsedGpuPumpMs=std::chrono::duration<double,std::milli>(
|
||||
std::chrono::steady_clock::now()-GpuPumpFrameStart).count();
|
||||
const double RemainingGpuPumpMs=StartupGpuPumpFrameBudgetMilliseconds
|
||||
-ElapsedGpuPumpMs;
|
||||
if(RemainingGpuPumpMs<=0.0)break;
|
||||
PumpGpuFarGeneration(RemainingGpuPumpMs);
|
||||
if(bGpuFarAuditEnabled||bInitialClipmapReported
|
||||
||GpuFarSubmissionBatches==PreviousSubmissionCount)break;
|
||||
PreviousSubmissionCount=GpuFarSubmissionBatches;
|
||||
}
|
||||
}
|
||||
const auto GpuPumpEnd=std::chrono::steady_clock::now();
|
||||
const auto Now=std::chrono::steady_clock::now();
|
||||
if(FlightTargetCrossings>0&&bFullDetailReported&&!bFlightStarted)
|
||||
|
||||
Reference in new issue
Block a user