wip(standalone): GPU step 9 -- remote band closed by CPU fallback; CPU still wins whole view
Re-verified f2de8fe (hashes, walk 5,642/5,642, far topology 0 diffs vs CPU and
WARP, GPU survival). The remote LOD3/4 band was a direct-GPU coverage loss
(overlapping pixels identical, surface pieces missing, e.g. (6,2,0,lod3));
LOD3/4 now mesh on CPU, root cause in the GPU route still unidentified.
A minimal first-submit repro (pools, first-touch dispatch, device flags) did
not reproduce the 2.4 s stall. Whole view: CPU 1.438 s vs GPU 4.704 s median.
Crossing probe overflowed GPU output slots: no valid crossing latency.
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
f2de8fe9c6
commit
b0da995978
21 files changed
+698
-4
No files matched your search
@@ -1323,6 +1323,7 @@ namespace
|
||||
ID3D11Buffer* VertexBuffer=nullptr;
|
||||
ID3D11Buffer* IndexBuffer=nullptr;
|
||||
UINT IndexCount=0;
|
||||
UINT DrawOnlyIndexStart=0,DrawOnlyIndexCount=0;
|
||||
uint64 VertexCount=0;
|
||||
};
|
||||
struct FCrossingWork
|
||||
@@ -1534,6 +1535,7 @@ namespace
|
||||
bool bAutoCaptureWritten=false;
|
||||
bool bFullDetailReported=false;
|
||||
bool bInitialClipmapReported=false;
|
||||
bool bWholeViewPresented=false;
|
||||
bool bProfileAttribution=false;
|
||||
bool bProfileDetailBand=false;
|
||||
bool bCompareEvaluators=false;
|
||||
@@ -1567,6 +1569,8 @@ namespace
|
||||
int32 CaptureOnlyLod=-1;
|
||||
bool bCaptureOnlyTile=false;
|
||||
int32 CaptureOnlyTileX=0,CaptureOnlyTileY=0,CaptureOnlyTileZ=0,CaptureOnlyTileLod=0;
|
||||
bool bDrawOnlyTile=false;
|
||||
int32 DrawOnlyTileX=0,DrawOnlyTileY=0,DrawOnlyTileZ=0,DrawOnlyTileLod=0;
|
||||
int32 CaptureOutputSlot=-1;
|
||||
int32 Width=1280,Height=800;
|
||||
float Yaw=0.0f,Pitch=0.0f,MoveSpeed=8.0f;
|
||||
@@ -1683,6 +1687,12 @@ namespace
|
||||
V3 Forward() const
|
||||
{return Normalize({std::sin(Yaw)*std::cos(Pitch),std::cos(Yaw)*std::cos(Pitch),std::sin(Pitch)});}
|
||||
|
||||
bool IsDrawOnlyTile(const FVoxelTileKey& Key) const
|
||||
{
|
||||
return !bDrawOnlyTile||(Key.Level==DrawOnlyTileLod&&Key.Coord.X==DrawOnlyTileX
|
||||
&&Key.Coord.Y==DrawOnlyTileY&&Key.Coord.Z==DrawOnlyTileZ);
|
||||
}
|
||||
|
||||
FIntVector CameraChunk() const
|
||||
{return StandaloneWorldMesher::CameraChunk(FVector(Position.X*4.0,Position.Y*4.0,Position.Z*4.0));}
|
||||
|
||||
@@ -2104,7 +2114,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
std::chrono::duration<double,std::milli>(std::chrono::steady_clock::now()-ColdProcessStart).count());
|
||||
const FVector CameraVoxels(Position.X*4.0,Position.Y*4.0,Position.Z*4.0);
|
||||
BuildTargetChunk=StandaloneWorldMesher::CameraChunk(CameraVoxels);
|
||||
bFullDetailReported=false;bInitialClipmapReported=false;bAutoCaptureWritten=false;
|
||||
bFullDetailReported=false;bInitialClipmapReported=false;bWholeViewPresented=false;bAutoCaptureWritten=false;
|
||||
if(bProfileAttribution)
|
||||
{
|
||||
VoxelDensityProfile::SetMode(VoxelDensityProfile::EMode::Attribution,128);
|
||||
@@ -2174,6 +2184,20 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
}
|
||||
DesiredTileSet.clear();DesiredTileSet.reserve(DesiredTiles.size()*2+1);
|
||||
for(const FVoxelTileKey& Key:DesiredTiles)DesiredTileSet.insert(Key);
|
||||
if(bDrawOnlyTile)
|
||||
{
|
||||
const FVoxelTileKey DrawKey(FIntVector(DrawOnlyTileX,DrawOnlyTileY,DrawOnlyTileZ),
|
||||
DrawOnlyTileLod);
|
||||
if(!DesiredTileSet.contains(DrawKey))
|
||||
{
|
||||
Error="the requested draw-only tile is not in the full desired clipmap";
|
||||
std::fprintf(stderr,"World load failed: %s\n",Error.c_str());
|
||||
PostMessageA(Window,WM_CLOSE,0,0);
|
||||
return;
|
||||
}
|
||||
std::printf("[DrawOnlyTile] key=(%d,%d,%d,lod%d) desired_targets=%zu filter=draw_only\n",
|
||||
DrawOnlyTileX,DrawOnlyTileY,DrawOnlyTileZ,DrawOnlyTileLod,DesiredTiles.size());
|
||||
}
|
||||
for(int32 I=0;I<=MaxLevels;++I)DesiredByLevel[I]=0;
|
||||
for(const FVoxelTileKey& Tile:DesiredTiles)++DesiredByLevel[Tile.Level];
|
||||
const int32 StreamWorkers=bShapePipelineActive?(WorkerCount>=8?2:1):WorkerCount;
|
||||
@@ -2434,10 +2458,21 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
std::vector<FVoxelTileKey> CpuTiles;CpuTiles.reserve(Keys.size());
|
||||
std::vector<FVoxelTileKey> Eligible;Eligible.reserve(Keys.size());
|
||||
uint64 SkirtTransitionFallbackTiles=0;
|
||||
uint64 RemoteLod3CpuFallbackTiles=0,RemoteLod4CpuFallbackTiles=0;
|
||||
for(const FVoxelTileKey& Key:Keys)
|
||||
{
|
||||
const VoxelForgeCore::TileKey CoreKey{{Key.Coord.X,Key.Coord.Y,Key.Coord.Z},Key.Level};
|
||||
const bool NearGpuEligible=Key.Level<World->FullResClipLevels;
|
||||
if(Key.Level==3||Key.Level==4)
|
||||
{
|
||||
CpuTiles.push_back(Key);
|
||||
if(Key.Level==3)++RemoteLod3CpuFallbackTiles;
|
||||
else ++RemoteLod4CpuFallbackTiles;
|
||||
if(bDrawOnlyTile&&IsDrawOnlyTile(Key))
|
||||
std::printf("[DrawOnlyTileRoute] key=(%d,%d,%d,lod%d) route=cpu_remote_band_fallback\n",
|
||||
Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level);
|
||||
continue;
|
||||
}
|
||||
if(NearGpuEligible||ShapeWorld->isFarFieldTileEligible(CoreKey))
|
||||
{
|
||||
const uint8 VisibleSkirtFaces=World->bGenerateSkirts
|
||||
@@ -2464,7 +2499,15 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
else Eligible.push_back(Key);
|
||||
}
|
||||
else CpuTiles.push_back(Key);
|
||||
if(bDrawOnlyTile&&IsDrawOnlyTile(Key))
|
||||
std::printf("[DrawOnlyTileRoute] key=(%d,%d,%d,lod%d) route=%s\n",
|
||||
Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level,
|
||||
Eligible.empty()||Eligible.back()!=Key?"cpu_fallback":"gpu_eligible");
|
||||
}
|
||||
if(RemoteLod3CpuFallbackTiles+RemoteLod4CpuFallbackTiles>0)
|
||||
std::printf("[GpuRemoteBandFallback] lod3_cpu_tiles=%llu lod4_cpu_tiles=%llu reason=remote_capture_pixel_coverage\n",
|
||||
static_cast<unsigned long long>(RemoteLod3CpuFallbackTiles),
|
||||
static_cast<unsigned long long>(RemoteLod4CpuFallbackTiles));
|
||||
if(Eligible.size()>GpuFarOutputCapacitySlots)
|
||||
{
|
||||
for(auto& Pair:GpuFarTiles)ReleaseGpuFarTile(Pair.second);
|
||||
@@ -3027,9 +3070,11 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
{std::fprintf(stderr,"LOD %d batch exceeded D3D11 limits.\n",Key.Level);return false;}
|
||||
std::vector<FGpuVertex> Vertices;Vertices.reserve(VertexCount);
|
||||
std::vector<uint32> Indices;Indices.reserve(IndexCount);
|
||||
UINT DrawOnlyIndexStart=0,DrawOnlyIndexCount=0;
|
||||
for(const FVoxelTileKey& Tile:Members)
|
||||
{
|
||||
const auto It=ResidentTiles.find(Tile);if(It==ResidentTiles.end())continue;
|
||||
const size_t TileIndexStart=Indices.size();
|
||||
const uint32 Base=static_cast<uint32>(Vertices.size());
|
||||
const FResidentTileMesh& Resident=It->second;
|
||||
for(const FStandaloneCpuVertex& V:Resident.Vertices)
|
||||
@@ -3047,6 +3092,11 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
Indices.push_back(Base+Resident.Indices[Start+1]);
|
||||
Indices.push_back(Base+Resident.Indices[Start+2]);
|
||||
}
|
||||
if(bDrawOnlyTile&&IsDrawOnlyTile(Tile))
|
||||
{
|
||||
DrawOnlyIndexStart=static_cast<UINT>(TileIndexStart);
|
||||
DrawOnlyIndexCount=static_cast<UINT>(Indices.size()-TileIndexStart);
|
||||
}
|
||||
}
|
||||
FStreamingGpuBatch NewBatch;
|
||||
const bool bVertex=MakeBuffer(&NewBatch.VertexBuffer,Vertices.data(),Vertices.size()*sizeof(FGpuVertex),D3D11_BIND_VERTEX_BUFFER);
|
||||
@@ -3058,6 +3108,8 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
return false;
|
||||
}
|
||||
NewBatch.IndexCount=static_cast<UINT>(Indices.size());NewBatch.VertexCount=Vertices.size();
|
||||
NewBatch.DrawOnlyIndexStart=DrawOnlyIndexStart;
|
||||
NewBatch.DrawOnlyIndexCount=DrawOnlyIndexCount;
|
||||
if(Existing!=StreamingBatches.end())
|
||||
{
|
||||
TotalVertices-=Existing->second.VertexCount;TotalIndices-=Existing->second.IndexCount;
|
||||
@@ -3459,9 +3511,13 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
const FStreamingGpuBatch& L=Pair.second;
|
||||
if(!bShowLevel[Pair.first.Level]
|
||||
||(CaptureOnlyLod>=0&&Pair.first.Level!=CaptureOnlyLod)
|
||||
||!L.VertexBuffer||!L.IndexBuffer||!L.IndexCount)continue;
|
||||
||!L.VertexBuffer||!L.IndexBuffer||!L.IndexCount
|
||||
||(bDrawOnlyTile&&L.DrawOnlyIndexCount==0))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);
|
||||
Context->IASetIndexBuffer(L.IndexBuffer,DXGI_FORMAT_R32_UINT,0);
|
||||
if(bDrawOnlyTile)
|
||||
Context->DrawIndexed(L.DrawOnlyIndexCount,L.DrawOnlyIndexStart,0);
|
||||
else Context->DrawIndexed(L.IndexCount,0,0);
|
||||
}
|
||||
// Avoid issuing hundreds of tiny indirect draw calls while the
|
||||
// initial far batches are still being built. Once the clipmap is
|
||||
@@ -3474,7 +3530,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
for(auto& Pair:GpuFarTiles)
|
||||
{
|
||||
FGpuFarTile& Tile=Pair.second;
|
||||
if(!bShowLevel[Pair.first.Level]
|
||||
if(!IsDrawOnlyTile(Pair.first)||!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;
|
||||
@@ -3580,6 +3636,15 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
const auto PresentCallStart=std::chrono::steady_clock::now();
|
||||
const HRESULT PresentResult=SwapChain->Present(PresentSyncInterval,PresentFlags);
|
||||
const auto PresentCallEnd=std::chrono::steady_clock::now();
|
||||
if(bInitialClipmapReported&&!bWholeViewPresented)
|
||||
{
|
||||
bWholeViewPresented=true;
|
||||
std::printf("[WholeViewPresented] at_ms=%.3f 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);
|
||||
}
|
||||
if(bGpuWarmupHoldReported&&!bGpuWarmupReleaseReported)
|
||||
{
|
||||
bGpuWarmupReleaseReported=true;
|
||||
@@ -5533,6 +5598,14 @@ int main(int Argc,char** Argv)
|
||||
App.bCaptureOnlyTile=true;
|
||||
else {std::fprintf(stderr,"Invalid --capture-only-tile value: %s\n",Values.c_str());return 2;}
|
||||
}
|
||||
else if(Arg.starts_with("--draw-only-tile="))
|
||||
{
|
||||
const std::string Values(Arg.substr(std::string_view("--draw-only-tile=").size()));
|
||||
if(std::sscanf(Values.c_str(),"%d,%d,%d,%d",&App.DrawOnlyTileX,
|
||||
&App.DrawOnlyTileY,&App.DrawOnlyTileZ,&App.DrawOnlyTileLod)==4)
|
||||
App.bDrawOnlyTile=true;
|
||||
else {std::fprintf(stderr,"Invalid --draw-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()));
|
||||
|
||||
Reference in new issue
Block a user