wip(standalone): GPU step 8 partial -- GPU skirts, first-present hold; remote gap open
Luna's session ended on an API "Bad Request" before a final report; state is unverified by me. In the log: GPU clipped-skirt emitter (count/scan/emit, protected signs and critical air honoured), exposed-skirt audit passing at the end; first-present stall reproduced on every launch (2.36-2.59 s, not exe identity/idle/CPU run) and hidden by holding the CPU-ready frame until GPU residency. Remote LOD3-4 band still differs from CPU; draw ranges and the one inspected LOD3 tile match, cause not yet found (one-tile probe mid-fix). 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
90421d0655
commit
f2de8fe9c6
42 files changed
+1381
-59
No files matched your search
@@ -1361,6 +1361,8 @@ namespace
|
||||
VoxelForgeGpuFarViewer::GpuTimingQueries TimingQueries{};
|
||||
uint64 VertexCapacityBytes=0;
|
||||
uint32 OutputSlot=0,IndirectArgsByteOffset=0,BatchIndex=UINT32_MAX;
|
||||
uint8 VisibleSkirtFaceMask=0;
|
||||
bool bSkirtDrawArgsAudited=false;
|
||||
double GpuDispatchMs=0.0;
|
||||
bool bGpuComplete=false;
|
||||
bool bTimingResolved=false;
|
||||
@@ -1486,13 +1488,26 @@ namespace
|
||||
bool bGpuFarEnabled=false;
|
||||
bool bGpuFarAuditEnabled=false;
|
||||
bool bGpuFarAuditReported=false;
|
||||
bool bGpuSkirtEmitEnabled=true,bGpuConnectorRepairEnabled=true;
|
||||
bool bDisableVSync=false;
|
||||
bool bForceBlockingStartupPresent=false;
|
||||
bool bPresentCpuFrameBeforeGpu=false;
|
||||
bool bCpuReadyFramePresentedBeforeGpu=false;
|
||||
bool bHoldCpuFrameDuringGpuWarmup=false,bGpuWarmupHoldReported=false;
|
||||
bool bGpuWarmupReleaseReported=false;
|
||||
uint64 GpuWarmupHeldPresents=0;
|
||||
bool bAuditGpuSkirtDrawArgs=false,bGpuSkirtDrawAuditReported=false;
|
||||
ID3D11Buffer* GpuSkirtArgsStaging=nullptr;
|
||||
uint64 GpuSkirtDrawAuditTiles=0,GpuSkirtDrawAuditZeroCounts=0,
|
||||
GpuSkirtDrawAuditOverflow=0,GpuSkirtDrawAuditBadStartIndex=0;
|
||||
uint64 GpuSkirtDrawAuditSumIndices=0,GpuSkirtDrawAuditMaxIndices=0;
|
||||
std::unique_ptr<FFarSurvivalAudit> GpuFarAudit;
|
||||
bool bGpuFarFirstTileReported=false;
|
||||
std::filesystem::path GpuFarShaderPath;
|
||||
double GpuFarEnqueueWallSeconds=0.0;
|
||||
uint64 GpuFarTilesSubmitted=0;
|
||||
uint64 PresentCallCount=0;
|
||||
uint64 StartupNonBlockingPresentCalls=0,StartupNonBlockingPresentSkips=0;
|
||||
double GpuFarGpuDispatchMs=0.0;
|
||||
double GpuFarGpuDispatchMaxMs=0.0;
|
||||
double GpuFarSubmissionSpanMs=0.0,GpuFarSubmissionSpanMaxMs=0.0;
|
||||
@@ -1549,6 +1564,10 @@ namespace
|
||||
int32 ClipRadius=3;
|
||||
int32 MaxClipLevelOverride=-1;
|
||||
int32 CaptureTileLimit=0;
|
||||
int32 CaptureOnlyLod=-1;
|
||||
bool bCaptureOnlyTile=false;
|
||||
int32 CaptureOnlyTileX=0,CaptureOnlyTileY=0,CaptureOnlyTileZ=0,CaptureOnlyTileLod=0;
|
||||
int32 CaptureOutputSlot=-1;
|
||||
int32 Width=1280,Height=800;
|
||||
float Yaw=0.0f,Pitch=0.0f,MoveSpeed=8.0f;
|
||||
V3 Position{};
|
||||
@@ -1565,6 +1584,7 @@ namespace
|
||||
StopGeneration(true);ReleaseMeshes();
|
||||
if(SolidRasterizer)SolidRasterizer->Release();if(WireRasterizer)WireRasterizer->Release();
|
||||
if(Constants)Constants->Release();if(InputLayout)InputLayout->Release();
|
||||
if(GpuSkirtArgsStaging)GpuSkirtArgsStaging->Release();
|
||||
if(VertexShader)VertexShader->Release();if(PixelShader)PixelShader->Release();
|
||||
if(RenderTarget)RenderTarget->Release();if(DepthView)DepthView->Release();
|
||||
if(SwapChain)SwapChain->Release();if(Context)Context->Release();if(Device)Device->Release();
|
||||
@@ -2101,6 +2121,24 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
for(const auto& Key:CoreTiles)
|
||||
DesiredTiles.emplace_back(FIntVector(Key.coordinate.x,Key.coordinate.y,Key.coordinate.z),Key.lod);
|
||||
}
|
||||
if(bCaptureOnlyTile)
|
||||
{
|
||||
const size_t Before=DesiredTiles.size();
|
||||
DesiredTiles.erase(std::remove_if(DesiredTiles.begin(),DesiredTiles.end(),[&](const FVoxelTileKey& Key)
|
||||
{
|
||||
return Key.Level!=CaptureOnlyTileLod||Key.Coord.X!=CaptureOnlyTileX
|
||||
||Key.Coord.Y!=CaptureOnlyTileY||Key.Coord.Z!=CaptureOnlyTileZ;
|
||||
}),DesiredTiles.end());
|
||||
std::printf("[CaptureOnlyTile] key=(%d,%d,%d,lod%d) before=%zu selected=%zu\n",
|
||||
CaptureOnlyTileX,CaptureOnlyTileY,CaptureOnlyTileZ,CaptureOnlyTileLod,
|
||||
Before,DesiredTiles.size());
|
||||
if(DesiredTiles.empty())
|
||||
{
|
||||
Error="the requested capture-only tile is not in the desired clipmap";
|
||||
std::fprintf(stderr,"World load failed: %s\n",Error.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(CaptureTileLimit>0&&CapturePath.size())
|
||||
{
|
||||
const size_t Before=DesiredTiles.size();
|
||||
@@ -2155,7 +2193,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
}
|
||||
}
|
||||
if(bShapePipelineActive)Streamer->SetDesiredTileFilter(InitialNeighborhoodTiles);
|
||||
else if(CaptureTileLimit>0&&CapturePath.size())
|
||||
else if((CaptureTileLimit>0&&CapturePath.size())||bCaptureOnlyTile)
|
||||
Streamer->SetDesiredTileFilter(DesiredTiles);
|
||||
const FStandaloneStreamingUpdate Update=Streamer->Start(CameraVoxels,{},CrossingIndex);
|
||||
if(bShapePipelineActive&&Update.DesiredTiles!=static_cast<int32>(InitialNeighborhoodTiles.size()))
|
||||
@@ -2343,6 +2381,20 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
Inputs[Index]=Key.Level<World->FullResClipLevels
|
||||
?ShapeWorld->exportGpuFieldTile(CoreKey,Errors[Index])
|
||||
:ShapeWorld->exportFarFieldTile(CoreKey,Errors[Index]);
|
||||
if(Inputs[Index]&&Key.Level>=World->FullResClipLevels)
|
||||
{
|
||||
Inputs[Index]->visibleSkirtFaceMask=World->bGenerateSkirts
|
||||
&&bGpuSkirtEmitEnabled
|
||||
?ComputeVisibleSkirtFaceMask(Key,DesiredTileSet):0;
|
||||
Inputs[Index]->skirtDepthVoxels=std::max(1.0f,
|
||||
static_cast<float>(World->SkirtCells))*Key.StepVoxels();
|
||||
if(!bGpuConnectorRepairEnabled)
|
||||
{
|
||||
Inputs[Index]->connectorPanels.clear();
|
||||
Inputs[Index]->connectorRingCount=0;
|
||||
Inputs[Index]->connectorVertexCount=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(const std::exception& Error) { Errors[Index]=Error.what(); }
|
||||
}
|
||||
@@ -2390,12 +2442,22 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
{
|
||||
const uint8 VisibleSkirtFaces=World->bGenerateSkirts
|
||||
?ComputeVisibleSkirtFaceMask(Key,DesiredTileSet):0;
|
||||
if(VisibleSkirtFaces!=0)
|
||||
if(Key.Level>=World->FullResClipLevels)
|
||||
{
|
||||
// CPU tiles carry the established clipped LOD skirts. The GPU field
|
||||
// and marching-cubes outputs match the CPU surface, but currently do
|
||||
// not emit these seam curtains. Keep tiles with exposed LOD faces on
|
||||
// the reference mesh path until a GPU skirt kernel is available.
|
||||
const auto Existing=GpuFarTiles.find(Key);
|
||||
if(Existing!=GpuFarTiles.end()
|
||||
&&Existing->second.VisibleSkirtFaceMask!=VisibleSkirtFaces)
|
||||
{
|
||||
const uint32 ReusedSlot=Existing->second.OutputSlot;
|
||||
ReleaseGpuFarTile(Existing->second);
|
||||
GpuFarTiles.erase(Existing);
|
||||
GpuFarFreeOutputSlots.push_back(ReusedSlot);
|
||||
}
|
||||
}
|
||||
if(VisibleSkirtFaces!=0&&NearGpuEligible)
|
||||
{
|
||||
// Keep fine tiles on the CPU reference path. Far tiles carry the
|
||||
// CPU-decided visible face mask to the deterministic GPU skirt pass.
|
||||
CpuTiles.push_back(Key);
|
||||
++SkirtTransitionFallbackTiles;
|
||||
}
|
||||
@@ -2411,6 +2473,14 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
}
|
||||
if(!Eligible.empty()&&GpuFarOutputCapacitySlots==0)
|
||||
GpuFarOutputCapacitySlots=static_cast<uint32>(Eligible.size());
|
||||
if(bCaptureOnlyTile&&CaptureOutputSlot>=0)
|
||||
{
|
||||
GpuFarOutputCapacitySlots=std::max(GpuFarOutputCapacitySlots,
|
||||
static_cast<uint32>(CaptureOutputSlot+1));
|
||||
GpuFarNextOutputSlot=static_cast<uint32>(CaptureOutputSlot);
|
||||
std::printf("[CaptureOutputSlotProbe] slot=%d pool_slots=%u\n",
|
||||
CaptureOutputSlot,GpuFarOutputCapacitySlots);
|
||||
}
|
||||
if(!Eligible.empty())
|
||||
{
|
||||
std::string PoolError;const auto ReserveStart=std::chrono::steady_clock::now();
|
||||
@@ -2473,7 +2543,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
{return Key.Level<World->FullResClipLevels;}));
|
||||
std::printf("[GpuFieldEligibility] eligible_gpu_tiles=%zu near_gpu_tiles=%zu cpu_fallback_tiles=%zu\n",
|
||||
GpuFarEligibleTiles.size(),NearGpuTiles,Keys.size()-GpuFarEligibleTiles.size());
|
||||
std::printf("[GpuSkirtSeamFallback] tiles=%llu reason=visible_lod_skirt_faces status=active\n",
|
||||
std::printf("[GpuSkirtSeamFallback] near_tiles=%llu reason=fine_visible_lod_skirts gpu_far_skirts=active\n",
|
||||
static_cast<unsigned long long>(SkirtTransitionFallbackTiles));
|
||||
}
|
||||
|
||||
@@ -2533,6 +2603,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
bGpuFarEnabled=false;
|
||||
break;
|
||||
}
|
||||
const uint8 PreparedSkirtFaceMask=PreparedInput->visibleSkirtFaceMask;
|
||||
if(!VoxelForgeGpuFarViewer::BuildFarTile(Device,Context,*ShapeWorld,CoreKey,
|
||||
PreparedInput,
|
||||
GpuFarShaderPath,&Tile.VertexBuffer,&Tile.IndexBuffer,&Tile.IndirectArgs,
|
||||
@@ -2565,6 +2636,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
}
|
||||
Tile.VertexCapacityBytes=static_cast<uint64>(
|
||||
VoxelForgeGpuFarViewer::PooledOutputVertexCapacityPerTile)*32u;
|
||||
Tile.VisibleSkirtFaceMask=PreparedSkirtFaceMask;
|
||||
Tile.GpuDispatchMs=GpuDispatchMs;
|
||||
GpuFarEnqueueWallSeconds+=EnqueueMs/1000.0;
|
||||
if(GpuDispatchMs>0.0)
|
||||
@@ -2643,6 +2715,9 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
bGpuFarEnabled=!bGpuFarEnabled;
|
||||
if(bGpuFarEnabled)
|
||||
{
|
||||
bPresentCpuFrameBeforeGpu=true;
|
||||
bHoldCpuFrameDuringGpuWarmup=true;
|
||||
bCpuReadyFramePresentedBeforeGpu=false;
|
||||
ScheduleGpuFarTiles(DesiredTiles);
|
||||
std::vector<FVoxelTileKey> CpuFar;
|
||||
for(const FVoxelTileKey& Key:DesiredTiles)
|
||||
@@ -3241,6 +3316,10 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
static_cast<unsigned long long>(TotalIndices),StreamingBatches.size());
|
||||
std::printf("[ColdTimeline] event=whole_clipmap_ready at_ms=%.3f waits_for=%zu_GPU_tiles_plus_CPU_fallback_and_uploads\n",
|
||||
Elapsed*1000.0,GpuFarEligibleTiles.size());
|
||||
std::printf("[PresentStartupSummary] nonblocking_startup_calls=%llu skipped_busy_calls=%llu gpu_warmup_held_calls=%llu policy=do_not_wait_until_initial_clipmap_ready\n",
|
||||
static_cast<unsigned long long>(StartupNonBlockingPresentCalls),
|
||||
static_cast<unsigned long long>(StartupNonBlockingPresentSkips),
|
||||
static_cast<unsigned long long>(GpuWarmupHeldPresents));
|
||||
if(bGpuFarEnabled)
|
||||
{
|
||||
SampleGpuFarMemory();
|
||||
@@ -3307,7 +3386,10 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
|
||||
void UpdateTitle()
|
||||
{
|
||||
uint64 VisibleIndices=0;for(const auto& Pair:StreamingBatches)if(bShowLevel[Pair.first.Level])VisibleIndices+=Pair.second.IndexCount;
|
||||
uint64 VisibleIndices=0;for(const auto& Pair:StreamingBatches)
|
||||
if(bShowLevel[Pair.first.Level]
|
||||
&&(CaptureOnlyLod<0||Pair.first.Level==CaptureOnlyLod))
|
||||
VisibleIndices+=Pair.second.IndexCount;
|
||||
std::ostringstream S;S<<"VoxelForge standalone | seed "<<Seed<<" | "<<(bShapeWorld?"shape-interval owner world":(bRoundTunnels?"round/winding research tunnels":"base world"))
|
||||
<<(bRoundTunnels?(bRoundTunnelEnhanced?" (detailed walls)":" (legacy walls)"):"")
|
||||
<<" | "<<VisibleIndices/3<<" tris | "<<FrameMs<<" ms | field "<<(bGpuFarEnabled?"GPU":"CPU")
|
||||
@@ -3323,7 +3405,9 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
?std::chrono::duration<double,std::milli>(DrawStart-LastDrawEndAt).count():0.0;
|
||||
PumpGeneration();
|
||||
const auto CpuPumpEnd=std::chrono::steady_clock::now();
|
||||
PumpGpuFarGeneration();
|
||||
const bool bDeferGpuUntilCpuFrame=bGpuFarEnabled&&bPresentCpuFrameBeforeGpu
|
||||
&&!bCpuReadyFramePresentedBeforeGpu;
|
||||
if(!bDeferGpuUntilCpuFrame)PumpGpuFarGeneration();
|
||||
const auto GpuPumpEnd=std::chrono::steady_clock::now();
|
||||
const auto Now=std::chrono::steady_clock::now();
|
||||
if(FlightTargetCrossings>0&&bFullDetailReported&&!bFlightStarted)
|
||||
@@ -3373,7 +3457,9 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
for(const auto& Pair:StreamingBatches)
|
||||
{
|
||||
const FStreamingGpuBatch& L=Pair.second;
|
||||
if(!bShowLevel[Pair.first.Level]||!L.VertexBuffer||!L.IndexBuffer||!L.IndexCount)continue;
|
||||
if(!bShowLevel[Pair.first.Level]
|
||||
||(CaptureOnlyLod>=0&&Pair.first.Level!=CaptureOnlyLod)
|
||||
||!L.VertexBuffer||!L.IndexBuffer||!L.IndexCount)continue;
|
||||
const UINT Stride=sizeof(FGpuVertex),Offset=0;Context->IASetVertexBuffers(0,1,&L.VertexBuffer,&Stride,&Offset);
|
||||
Context->IASetIndexBuffer(L.IndexBuffer,DXGI_FORMAT_R32_UINT,0);Context->DrawIndexed(L.IndexCount,0,0);
|
||||
}
|
||||
@@ -3385,12 +3471,59 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
C.Padding[0]=0.01f;
|
||||
Context->UpdateSubresource(Constants,0,nullptr,&C,0,0);
|
||||
Context->VSSetConstantBuffers(0,1,&Constants);Context->PSSetConstantBuffers(0,1,&Constants);
|
||||
for(const auto& Pair:GpuFarTiles)
|
||||
for(auto& Pair:GpuFarTiles)
|
||||
{
|
||||
const FGpuFarTile& Tile=Pair.second;
|
||||
if(!bShowLevel[Pair.first.Level]||!Tile.VertexBuffer||!Tile.IndexBuffer||!Tile.IndirectArgs)continue;
|
||||
FGpuFarTile& Tile=Pair.second;
|
||||
if(!bShowLevel[Pair.first.Level]
|
||||
||(CaptureOnlyLod>=0&&Pair.first.Level!=CaptureOnlyLod)
|
||||
||!Tile.VertexBuffer||!Tile.IndexBuffer||!Tile.IndirectArgs)continue;
|
||||
if(!bInitialClipmapReported&&Pair.first.Level>=World->FullResClipLevels)continue;
|
||||
if(!IsRenderedTileReady(Pair.first))continue;
|
||||
if(bAuditGpuSkirtDrawArgs&&Tile.VisibleSkirtFaceMask!=0&&!Tile.bSkirtDrawArgsAudited)
|
||||
{
|
||||
if(!GpuSkirtArgsStaging)
|
||||
{
|
||||
D3D11_BUFFER_DESC StagingDesc{};
|
||||
StagingDesc.ByteWidth=11u*sizeof(uint32);
|
||||
StagingDesc.Usage=D3D11_USAGE_STAGING;
|
||||
StagingDesc.CPUAccessFlags=D3D11_CPU_ACCESS_READ;
|
||||
const HRESULT CreateResult=Device->CreateBuffer(&StagingDesc,nullptr,
|
||||
&GpuSkirtArgsStaging);
|
||||
if(FAILED(CreateResult))
|
||||
std::fprintf(stderr,"[GpuSkirtDrawAuditError] create_staging_hr=0x%08lx\n",
|
||||
static_cast<unsigned long>(CreateResult));
|
||||
}
|
||||
if(GpuSkirtArgsStaging)
|
||||
{
|
||||
const D3D11_BOX ArgsSource{Tile.IndirectArgsByteOffset,0,0,
|
||||
Tile.IndirectArgsByteOffset+11u*sizeof(uint32),1,1};
|
||||
Context->CopySubresourceRegion(GpuSkirtArgsStaging,0,0,0,0,
|
||||
Tile.IndirectArgs,0,&ArgsSource);
|
||||
D3D11_MAPPED_SUBRESOURCE ArgsMapped{};
|
||||
const HRESULT MapResult=Context->Map(GpuSkirtArgsStaging,0,
|
||||
D3D11_MAP_READ,0,&ArgsMapped);
|
||||
if(SUCCEEDED(MapResult))
|
||||
{
|
||||
const auto* Args=static_cast<const uint32*>(ArgsMapped.pData);
|
||||
const uint32 ExpectedStartIndex=(Tile.IndirectArgsByteOffset
|
||||
/(11u*sizeof(uint32)))*32768u;
|
||||
++GpuSkirtDrawAuditTiles;
|
||||
GpuSkirtDrawAuditSumIndices+=Args[5];
|
||||
GpuSkirtDrawAuditMaxIndices=std::max<uint64>(GpuSkirtDrawAuditMaxIndices,Args[5]);
|
||||
if(Args[5]==0)++GpuSkirtDrawAuditZeroCounts;
|
||||
if(Args[10]!=0)++GpuSkirtDrawAuditOverflow;
|
||||
if(Args[7]!=ExpectedStartIndex)++GpuSkirtDrawAuditBadStartIndex;
|
||||
std::printf("[GpuSkirtDrawArgs] key=(%d,%d,%d,lod%d) face_mask=0x%02x output_slot=%u surface_indices=%u skirt_panel_indices=%u instances=%u connector_start_index=%u expected_start_index=%u overflow=%u\n",
|
||||
Pair.first.Coord.X,Pair.first.Coord.Y,Pair.first.Coord.Z,Pair.first.Level,
|
||||
static_cast<unsigned>(Tile.VisibleSkirtFaceMask),Tile.OutputSlot,
|
||||
Args[0],Args[5],Args[6],Args[7],ExpectedStartIndex,Args[10]);
|
||||
Context->Unmap(GpuSkirtArgsStaging,0);
|
||||
}
|
||||
else std::fprintf(stderr,"[GpuSkirtDrawAuditError] map_staging_hr=0x%08lx\n",
|
||||
static_cast<unsigned long>(MapResult));
|
||||
}
|
||||
Tile.bSkirtDrawArgsAudited=true;
|
||||
}
|
||||
const UINT Stride=32,Offset=0;
|
||||
Context->IASetVertexBuffers(0,1,&Tile.VertexBuffer,&Stride,&Offset);
|
||||
Context->IASetIndexBuffer(Tile.IndexBuffer,DXGI_FORMAT_R32_UINT,0);
|
||||
@@ -3404,20 +3537,84 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(bAuditGpuSkirtDrawArgs&&bInitialClipmapReported&&!bGpuSkirtDrawAuditReported)
|
||||
{
|
||||
std::printf("[GpuSkirtDrawArgsSummary] tiles=%llu zero_index_counts=%llu overflow=%llu bad_slot_start_indices=%llu total_panel_plus_skirt_indices=%llu max_panel_plus_skirt_indices=%llu status=%s\n",
|
||||
static_cast<unsigned long long>(GpuSkirtDrawAuditTiles),
|
||||
static_cast<unsigned long long>(GpuSkirtDrawAuditZeroCounts),
|
||||
static_cast<unsigned long long>(GpuSkirtDrawAuditOverflow),
|
||||
static_cast<unsigned long long>(GpuSkirtDrawAuditBadStartIndex),
|
||||
static_cast<unsigned long long>(GpuSkirtDrawAuditSumIndices),
|
||||
static_cast<unsigned long long>(GpuSkirtDrawAuditMaxIndices),
|
||||
(GpuSkirtDrawAuditTiles>0&&GpuSkirtDrawAuditOverflow==0
|
||||
&&GpuSkirtDrawAuditBadStartIndex==0)?"PASS":"FAIL");
|
||||
bGpuSkirtDrawAuditReported=true;
|
||||
std::fflush(stdout);
|
||||
}
|
||||
CaptureRenderedFrame();
|
||||
const bool bHoldFrontBufferForGpuWarmup=bHoldCpuFrameDuringGpuWarmup
|
||||
&&bCpuReadyFramePresentedBeforeGpu&&bGpuFarEnabled
|
||||
&&GpuFarTilesSubmitted>0&&!bInitialClipmapReported;
|
||||
if(bHoldFrontBufferForGpuWarmup)
|
||||
{
|
||||
if(!bGpuWarmupHoldReported)
|
||||
{
|
||||
bGpuWarmupHoldReported=true;
|
||||
std::printf("[GpuWarmupPresentHold] begin_ms=%.3f policy=retain_last_CPU_ready_front_buffer_until_GPU_clipmap_ready\n",
|
||||
std::chrono::duration<double,std::milli>(
|
||||
std::chrono::steady_clock::now()-ColdProcessStart).count());
|
||||
std::fflush(stdout);
|
||||
}
|
||||
++GpuWarmupHeldPresents;
|
||||
// Keep pumping CPU and GPU work at the display cadence without
|
||||
// calling the driver present path that stalls on its first GPU frame.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(11));
|
||||
LastDrawEndAt=std::chrono::steady_clock::now();
|
||||
return;
|
||||
}
|
||||
const auto BeforePresent=std::chrono::steady_clock::now();
|
||||
const UINT PresentSyncInterval=bDisableVSync?0u:1u;
|
||||
const bool bNonBlockingStartupPresent=bGpuFarEnabled&&!bInitialClipmapReported
|
||||
&&!bForceBlockingStartupPresent;
|
||||
const UINT PresentSyncInterval=(bDisableVSync||bNonBlockingStartupPresent)?0u:1u;
|
||||
const UINT PresentFlags=bNonBlockingStartupPresent?DXGI_PRESENT_DO_NOT_WAIT:0u;
|
||||
const auto PresentCallStart=std::chrono::steady_clock::now();
|
||||
SwapChain->Present(PresentSyncInterval,0);
|
||||
const HRESULT PresentResult=SwapChain->Present(PresentSyncInterval,PresentFlags);
|
||||
const auto PresentCallEnd=std::chrono::steady_clock::now();
|
||||
if(bGpuWarmupHoldReported&&!bGpuWarmupReleaseReported)
|
||||
{
|
||||
bGpuWarmupReleaseReported=true;
|
||||
std::printf("[GpuWarmupPresentRelease] at_ms=%.3f first_post_warmup_present_ms=%.3f sync=%u hr=0x%08lx\n",
|
||||
std::chrono::duration<double,std::milli>(PresentCallEnd-ColdProcessStart).count(),
|
||||
std::chrono::duration<double,std::milli>(PresentCallEnd-PresentCallStart).count(),
|
||||
PresentSyncInterval,static_cast<unsigned long>(PresentResult));
|
||||
std::fflush(stdout);
|
||||
}
|
||||
const uint64 PresentOrdinal=++PresentCallCount;
|
||||
if(bNonBlockingStartupPresent)
|
||||
{
|
||||
++StartupNonBlockingPresentCalls;
|
||||
if(PresentResult==DXGI_ERROR_WAS_STILL_DRAWING)++StartupNonBlockingPresentSkips;
|
||||
else if(FAILED(PresentResult))
|
||||
std::fprintf(stderr,"[PresentStartupError] hr=0x%08lx\n",
|
||||
static_cast<unsigned long>(PresentResult));
|
||||
}
|
||||
if(PresentOrdinal<=3)
|
||||
std::printf("[PresentProfile] ordinal=%llu at_ms=%.3f sync=%u call_ms=%.3f gpu_tiles_submitted=%llu gpu_batches=%llu\n",
|
||||
std::printf("[PresentProfile] ordinal=%llu at_ms=%.3f sync=%u flags=0x%08x mode=%s hr=0x%08lx call_ms=%.3f gpu_tiles_submitted=%llu gpu_batches=%llu\n",
|
||||
static_cast<unsigned long long>(PresentOrdinal),
|
||||
std::chrono::duration<double,std::milli>(PresentCallEnd-ColdProcessStart).count(),
|
||||
PresentSyncInterval,std::chrono::duration<double,std::milli>(PresentCallEnd-PresentCallStart).count(),
|
||||
PresentSyncInterval,PresentFlags,bNonBlockingStartupPresent?"startup-do-not-wait":"normal",
|
||||
static_cast<unsigned long>(PresentResult),
|
||||
std::chrono::duration<double,std::milli>(PresentCallEnd-PresentCallStart).count(),
|
||||
static_cast<unsigned long long>(GpuFarTilesSubmitted),
|
||||
static_cast<unsigned long long>(GpuFarSubmissionBatches));
|
||||
if(bDeferGpuUntilCpuFrame&&!StreamingBatches.empty())
|
||||
{
|
||||
bCpuReadyFramePresentedBeforeGpu=true;
|
||||
std::printf("[CpuReadyFrameBeforeGpu] at_ms=%.3f uploaded_cpu_batches=%zu next_action=submit_gpu_far\n",
|
||||
std::chrono::duration<double,std::milli>(PresentCallEnd-ColdProcessStart).count(),
|
||||
StreamingBatches.size());
|
||||
std::fflush(stdout);
|
||||
}
|
||||
UpdateTitle();
|
||||
const auto DrawEnd=std::chrono::steady_clock::now();
|
||||
const double CpuPumpMs=std::chrono::duration<double,std::milli>(CpuPumpEnd-DrawStart).count();
|
||||
@@ -5230,13 +5427,22 @@ int main(int Argc,char** Argv)
|
||||
const std::string_view Arg=Argv[I];
|
||||
if(Arg.starts_with("--capture="))App.CapturePath=std::string(Arg.substr(10));
|
||||
else if(Arg=="--no-vsync")App.bDisableVSync=true;
|
||||
else if(Arg=="--blocking-startup-present")App.bForceBlockingStartupPresent=true;
|
||||
else if(Arg=="--cpu-frame-before-gpu")App.bPresentCpuFrameBeforeGpu=true;
|
||||
else if(Arg=="--hold-cpu-frame-during-gpu-warmup")
|
||||
App.bHoldCpuFrameDuringGpuWarmup=true,App.bPresentCpuFrameBeforeGpu=true;
|
||||
else if(Arg=="--gpu-skirt-draw-audit")App.bAuditGpuSkirtDrawArgs=true;
|
||||
else if(Arg=="--gpu-skirts-disabled")App.bGpuSkirtEmitEnabled=false;
|
||||
else if(Arg=="--gpu-connectors-disabled")App.bGpuConnectorRepairEnabled=false;
|
||||
else if(Arg=="--profile-attribution")App.bProfileAttribution=true;
|
||||
else if(Arg=="--profile-detail-band")bProfileDetailBand=true;
|
||||
else if(Arg=="--compare-evaluators")App.bCompareEvaluators=true;
|
||||
else if(Arg=="--parity-only")App.bParityOnly=true;
|
||||
else if(Arg=="--density-hash")App.bDensityHash=true;
|
||||
else if(Arg=="--shape-world")App.bShapeWorld=true;
|
||||
else if(Arg=="--gpu-far")App.bGpuFarEnabled=true,App.bShapeWorld=true,App.bForceGenerate=true;
|
||||
else if(Arg=="--gpu-far")
|
||||
App.bGpuFarEnabled=true,App.bShapeWorld=true,App.bForceGenerate=true,
|
||||
App.bPresentCpuFrameBeforeGpu=true,App.bHoldCpuFrameDuringGpuWarmup=true;
|
||||
else if(Arg=="--cpu-far")App.bGpuFarEnabled=false,App.bShapeWorld=true,App.bForceGenerate=true;
|
||||
else if(Arg=="--gpu-far-audit")
|
||||
{App.bGpuFarEnabled=true;App.bGpuFarAuditEnabled=true;App.bShapeWorld=true;App.bForceGenerate=true;App.bQuitAfterClipmap=true;}
|
||||
@@ -5316,6 +5522,20 @@ int main(int Argc,char** Argv)
|
||||
else if(Arg.starts_with("--capture-tile-limit="))
|
||||
App.CaptureTileLimit=std::clamp(std::atoi(
|
||||
std::string(Arg.substr(std::string_view("--capture-tile-limit=").size())).c_str()),1,4096);
|
||||
else if(Arg.starts_with("--capture-only-lod="))
|
||||
App.CaptureOnlyLod=std::clamp(std::atoi(
|
||||
std::string(Arg.substr(std::string_view("--capture-only-lod=").size())).c_str()),0,8);
|
||||
else if(Arg.starts_with("--capture-only-tile="))
|
||||
{
|
||||
const std::string Values(Arg.substr(std::string_view("--capture-only-tile=").size()));
|
||||
if(std::sscanf(Values.c_str(),"%d,%d,%d,%d",&App.CaptureOnlyTileX,
|
||||
&App.CaptureOnlyTileY,&App.CaptureOnlyTileZ,&App.CaptureOnlyTileLod)==4)
|
||||
App.bCaptureOnlyTile=true;
|
||||
else {std::fprintf(stderr,"Invalid --capture-only-tile value: %s\n",Values.c_str());return 2;}
|
||||
}
|
||||
else if(Arg.starts_with("--capture-output-slot="))
|
||||
App.CaptureOutputSlot=std::max(-1,std::atoi(
|
||||
std::string(Arg.substr(std::string_view("--capture-output-slot=").size())).c_str()));
|
||||
else if(Arg.starts_with("--benchmark-level="))
|
||||
BenchmarkLevel=std::atoi(std::string(Arg.substr(18)).c_str());
|
||||
else if(Arg.starts_with("--benchmark-count="))
|
||||
@@ -5334,6 +5554,14 @@ int main(int Argc,char** Argv)
|
||||
}
|
||||
else if(!Arg.empty()&&Arg.front()!='-')App.DataPath=std::string(Arg);
|
||||
}
|
||||
if(App.bCaptureOnlyTile&&App.bGpuFarEnabled)
|
||||
{
|
||||
// A single far-tile probe may have no CPU fallback batch to present.
|
||||
// Let it submit directly instead of waiting for the normal CPU-first
|
||||
// presentation gate that requires a nonempty CPU batch.
|
||||
App.bPresentCpuFrameBeforeGpu=false;
|
||||
App.bHoldCpuFrameDuringGpuWarmup=false;
|
||||
}
|
||||
App.bProfileDetailBand=bProfileDetailBand;
|
||||
std::string Error;
|
||||
std::printf("[ColdTimeline] stage=owner_data_load begin_ms=%.3f\n",
|
||||
|
||||
Reference in new issue
Block a user