wip(standalone): GPU step 25 -- shape profile, roughness endpoint reuse, export before CPU frame; first launch REGRESSED

Luna: shape_compile profiled (8 workers, detail band ~323 ms of ~545 ms over 9.39M
candidates; roughness dominates). Exact vertical roughness endpoint reuse in
ShapeWorldInternal.h, hashes unchanged: ~548-577 -> ~535-548 ms. Overlapping
pipeline/pool with shape or streaming made things slower, so it stays serial (pool
precompile now 4-20 ms). Export starts before the first CPU frame. Marker-miss stall
reproduced and gated differently; the forced-cold survival audit now hits
DXGI 0x887A0005 (device removed) on a timestamp query and is NOT passing. Auto
survival passes (6.16 GB). The vertex count at InitialClipmapReady counts CPU
batches only (GPU-resident tiles excluded) -- confirmed counting, not missing geometry.

My runs outside the sandbox (Step25.exe, marker removed first, interleaved, -Timeline):
  CPU 1.329 / 1.295 / 1.318 s
  GPU cached 1.152 / 1.170 / 1.137 s, all 1,434 GPU tiles (timestamps 292 / 260 / 356 ms,
      max dispatch 19.0 / 15.9 / 75.2 ms)
  GPU marker miss 2.015 s -- REGRESSION vs step 24's 1.336 s. CPU had all 2,226 tiles by
      ~1.3 s, but near_all_tiles_ready waited for the post-view shader warmup
      (queue 1,025 ms, finished 1,955 ms; handoff cpu_started=1434 takeover=0).
Audits: hashes w1/w8, walk 5,642/5,642, near 960 / far 1,114 0 diffs vs CPU and
WARP, thin 353, ten captures 2+2 edge pixels as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-08 02:55:32 +02:00
1 parent 94d50edb47
commit 20acf57678
9 files changed
+380 -20

No files matched your search

+37 -9
View File
@@ -100,6 +100,10 @@ public:
double LocalPrimitiveSeconds = 0.0;
double LocalLineBinSeconds = 0.0;
double CandidateMergeSeconds = 0.0;
double DetailApplySeconds = 0.0;
double SignEdgeDistanceSeconds = 0.0;
double PassageValidationSeconds = 0.0;
double SharedFieldSeconds = 0.0;
double FarPrimitiveSeconds = 0.0;
double FarBinSeconds = 0.0;
FParallelTiming RockIntervalLines;
@@ -321,13 +325,21 @@ public:
Stats.IntervalSeconds=std::chrono::duration<double>(Clock::now()-Stage).count();
Stage=Clock::now();
Substage=Clock::now();
ApplyDetailBand(Stats.DetailBandLines);
Stats.DetailApplySeconds=std::chrono::duration<double>(Clock::now()-Substage).count();
Substage=Clock::now();
Stats.SurfaceProxyNodes+=CompleteSignEdgeDistances();
Stats.SignEdgeDistanceSeconds=std::chrono::duration<double>(Clock::now()-Substage).count();
Stats.SurfaceSeconds=std::chrono::duration<double>(Clock::now()-Stage).count();
// Route validation is world-wide. Detail regions reuse the same authored route data and
// do not need to repeat the 5,642-point world audit for every entering tile group.
Substage=Clock::now();
if(bValidatePassageRoutes)ValidatePassageRoutes();
Stats.PassageValidationSeconds=std::chrono::duration<double>(Clock::now()-Substage).count();
Substage=Clock::now();
RebuildSharedFieldPrimitives();
Stats.SharedFieldSeconds=std::chrono::duration<double>(Clock::now()-Substage).count();
Built=true;
if(bIncludeFarWorld)BuildFarWorld();
const uint64 WordBytes=static_cast<uint64>(RockWords.size()+CandidateWords.size())*sizeof(uint64);
@@ -348,6 +360,10 @@ public:
Stats.CandidateMergeLines.WallSeconds*1000.0,Stats.CandidateMergeLines.WorkerSeconds*1000.0,
Stats.CandidateMergeSeconds*1000.0,Stats.DetailBandLines.WallSeconds*1000.0,
Stats.DetailBandLines.WorkerSeconds*1000.0);
std::printf("[ShapeSubstage] detail_apply=%.3fms sign_edge_distances=%.3fms passage_validation=%.3fms shared_field_primitives=%.3fms far_parents=%.3fms\n",
Stats.DetailApplySeconds*1000.0,Stats.SignEdgeDistanceSeconds*1000.0,
Stats.PassageValidationSeconds*1000.0,Stats.SharedFieldSeconds*1000.0,
Stats.FarShapeSeconds*1000.0);
std::printf("[ShapeAllocation] words=%.2fMiB candidate_axis_words=%.2fMiB proxy=%.2fMiB primitives=%.2fMiB spatial_bins=%llu spatial_bin_refs=%llu spatial_bin_capacity=%llu inline_bins=%llu overflow_bins=%llu far_primitive_build=%.3fms far_bin_rebuild=%.3fms\n",
static_cast<double>(WordBytes)/1048576.0,static_cast<double>(CandidateAxisBytes)/1048576.0,
static_cast<double>(Stats.SignNodes*sizeof(int16))/1048576.0,
@@ -4118,9 +4134,13 @@ private:
struct FOwnerNoiseLineContext
{
const FLayerField* Field=nullptr;
int32 GridZ0=MIN_int32;
float LowerCore=0.0f,UpperCore=0.0f;
struct FAnchorCache
{
const FLayerField* Field=nullptr;
int32 GridZ0=MIN_int32;
int32 SampleZ0=MIN_int32,SampleZ1=MIN_int32;
float LowerCore=0.0f,UpperCore=0.0f;
} Step8,Step2;
};
float OwnerCaveRoughnessCore(double X,double Y,double Z,
@@ -4153,7 +4173,10 @@ private:
Total=OwnerCaveRoughnessCore(X,Y,Z,Params);
else if(SampleZ1>SampleZ0)
{
const bool bCacheHit=LineContext.Field==&Field&&LineContext.GridZ0==GridZ0;
FOwnerNoiseLineContext::FAnchorCache& Cache=ZStep==2
?LineContext.Step2:LineContext.Step8;
const bool bCacheHit=Cache.Field==&Field&&Cache.GridZ0==GridZ0
&&Cache.SampleZ0==SampleZ0&&Cache.SampleZ1==SampleZ1;
if(Profile)
{
if(bCacheHit)++Profile->OwnerNoiseCacheHits;
@@ -4161,13 +4184,18 @@ private:
}
if(!bCacheHit)
{
LineContext.Field=&Field;
LineContext.GridZ0=GridZ0;
LineContext.LowerCore=OwnerCaveRoughnessCore(X,Y,SampleZ0,Params);
LineContext.UpperCore=OwnerCaveRoughnessCore(X,Y,SampleZ1,Params);
const bool bReusesPreviousUpper=Cache.Field==&Field
&&Cache.SampleZ1==SampleZ0;
Cache.Field=&Field;
Cache.GridZ0=GridZ0;
Cache.SampleZ0=SampleZ0;
Cache.SampleZ1=SampleZ1;
Cache.LowerCore=bReusesPreviousUpper?Cache.UpperCore
:OwnerCaveRoughnessCore(X,Y,SampleZ0,Params);
Cache.UpperCore=OwnerCaveRoughnessCore(X,Y,SampleZ1,Params);
}
const float Alpha=static_cast<float>((Z-SampleZ0)/(SampleZ1-SampleZ0));
Total=FMath::Lerp(LineContext.LowerCore,LineContext.UpperCore,Alpha);
Total=FMath::Lerp(Cache.LowerCore,Cache.UpperCore,Alpha);
}
else
Total=OwnerCaveRoughnessCore(X,Y,Z,Params);