#include "OwnerWorldLoader.h" #include "StreamingWorld.h" #include "StandaloneCoreScheduler.h" #include "../Core/src/StandaloneSnapshotAdapter.h" #include "../Research/OwnerShapeWorld/gpu_field_port/GpuFarViewer.h" #include "VoxelDensityProfile.h" #ifdef TEXT #undef TEXT #endif #ifndef NOMINMAX #define NOMINMAX #endif #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #pragma comment(lib,"d3d11.lib") #pragma comment(lib,"dxgi.lib") #pragma comment(lib,"d3dcompiler.lib") #pragma comment(lib,"user32.lib") #pragma comment(lib,"gdi32.lib") namespace { struct V3 { float X=0.0f,Y=0.0f,Z=0.0f; }; V3 Add(V3 A,V3 B){return {A.X+B.X,A.Y+B.Y,A.Z+B.Z};} V3 Sub(V3 A,V3 B){return {A.X-B.X,A.Y-B.Y,A.Z-B.Z};} V3 Mul(V3 A,float S){return {A.X*S,A.Y*S,A.Z*S};} float Dot(V3 A,V3 B){return A.X*B.X+A.Y*B.Y+A.Z*B.Z;} V3 Cross(V3 A,V3 B){return {A.Y*B.Z-A.Z*B.Y,A.Z*B.X-A.X*B.Z,A.X*B.Y-A.Y*B.X};} V3 Normalize(V3 A){return Mul(A,1.0f/std::sqrt(std::max(1.0e-20f,Dot(A,A))));} #include "FarSurvivalAudit.h" struct FMeshSheetAudit { uint64 Components=0; uint64 SmallComponents=0; uint64 SmallComponentsInView=0; uint64 BoundarySmallComponentsInView=0; uint64 ThinSheets=0; uint64 TrianglesInThinSheets=0; double MinimumThicknessVoxels=std::numeric_limits::max(); }; struct FMeshArtifactAudit { uint64 Tiles=0,SurfaceVertices=0,EdgeVertices=0,MidpointVertices=0; uint64 SkirtTriangles=0,HiddenSameLodSkirtTriangles=0,ExposedSkirtTriangles=0, ReverseSideSolidSkirtTriangles=0,RepeatedOffsetPatches=0,FieldMismatchPatches=0, NormalMismatchPatches=0,GradientFallbackPatches=0,GradientFallbackSamples=0, DetailDisplacementSamples=0,HighDetailDisplacementSamples=0,DetailDisplacementPatches=0, CurvedEdgeChecks=0,CurvedEdgeRootPatches=0,CurvedEdgeRootBadVertices=0, DetailGradientSamples=0,DetailGradientOverLimit=0; double MaximumAirSkirtDensity=0.0,MaximumPatchDominance=0.0; double MaximumDetailDisplacement=0.0; double MaximumCurvedEdgeRootError=0.0; double MaximumDetailGradient=0.0; uint64 FieldEdgeChecks=0,AnalyticCrossingMisses=0,OldInt8RangeEdges=0,NormalChecks=0; double SumAbsSourceResidual=0.0,MaximumAbsSourceResidual=0.0, SumAnalyticEdgeShiftVoxels=0.0,MaximumAnalyticEdgeShiftVoxels=0.0, SumNormalAgreement=0.0,MinimumNormalAgreement=1.0; std::array WorstShiftPosition{},WorstResidualPosition{}; double WorstShiftFraction=0.0,WorstShiftD0=0.0,WorstShiftD1=0.0, WorstShiftExactD0=0.0,WorstShiftExactD1=0.0; int32 WorstShiftAxis=-1; std::array OffsetHistogram{}; }; uint8 ComputeVisibleSkirtFaceMask(const FVoxelTileKey& Tile, const std::unordered_set& Desired) { const FIntVector Origin=Tile.OriginVoxels(); const int32 Extent=Tile.ExtentVoxels(); const auto FloorDiv=[](int64 Value,int64 Divisor) { int64 Quotient=Value/Divisor; if(Value%Divisor<0)--Quotient; return static_cast(Quotient); }; uint8 Mask=0; for(int32 Axis=0;Axis<3;++Axis) for(int32 Side=0;Side<2;++Side) { int64 Probe[3]={Origin.X+Extent/2,Origin.Y+Extent/2,Origin.Z+Extent/2}; Probe[Axis]=Side?static_cast((&Origin.X)[Axis])+Extent :static_cast((&Origin.X)[Axis])-1; int32 NeighborLevel=-1; for(int32 Level=0;Level<=8;++Level) { const int64 NeighborExtent=static_cast(CHUNK_SIZE)<(1u<<(Axis*2+Side)); } return Mask; } FMeshArtifactAudit AuditMeshArtifacts(const FStandaloneCpuTile& Tile, const VoxelForgeCore::World& Shape,double SkirtDepthMeters,uint8 VisibleSkirtFaceMask, bool bPrintSkirts,bool bPrintPatches) { FMeshArtifactAudit Result; if(Tile.Key.Level<0||Tile.Key.Level>1||Tile.Vertices.empty()||Tile.Indices.size()<3) return Result; ++Result.Tiles; const size_t VertexCount=Tile.Vertices.size(); const size_t SurfaceVertices=std::min(Tile.SurfaceVertexCount,VertexCount); Result.SurfaceVertices=SurfaceVertices; const int32 Step=1<; // interpolated axis, then the 8-voxel block xyz struct FFieldBlock {uint64 Vertices=0,BadVertices=0;double MaximumShift=0.0,MaximumResidual=0.0; std::array Position{};}; struct FNormalBlock {uint64 Vertices=0,BadVertices=0;double MinimumAgreement=1.0; std::array Position{},MeshNormal{};}; struct FGradientFallbackBlock {uint64 Vertices=0,BadVertices=0,BadSamples=0;double MaximumError=0.0; std::array Position{};}; struct FCurvedEdgeRootBlock {uint64 Vertices=0,BadVertices=0;double MaximumError=0.0; std::array Position{};}; std::map> OffsetBlocks; std::map FieldBlocks; std::map NormalBlocks; std::map GradientFallbackBlocks; std::map CurvedEdgeRootBlocks; struct FDetailDisplacementBlock {uint64 Vertices=0,HighVertices=0;double Maximum=0.0,MaximumGradient=0.0;std::array Position{};}; std::map,FDetailDisplacementBlock> DetailDisplacementBlocks; std::map> FirstPositionByBlock; std::map> FirstNormalByBlock; uint64 RayTileResidualSamples=0,RayTileResidualGt01=0, RayTileResidualGt025=0,RayTileResidualGt05=0; double RayTileResidualSum=0.0,RayTileResidualMaximum=0.0; std::array RayTileResidualMaximumPosition{}; uint64 RayTileInteriorSamples=0,RayTileInteriorGt0125=0, RayTileInteriorGt025=0,RayTileInteriorGt05=0,RayTileInteriorGt1=0; double RayTileInteriorResidualSum=0.0,RayTileInteriorResidualMaximum=0.0; std::array RayTileInteriorMaximumPosition{}; for(size_t I=0;I=0.60f&&DetailSample.floorInfluence>=0.60f) { constexpr double GradientProbeOffset=0.5; double DetailGradientSquared=0.0; for(int32 Axis=0;Axis<3;++Axis) { double Minus[3]={P[0],P[1],P[2]}; double Plus[3]={P[0],P[1],P[2]}; Minus[Axis]-=GradientProbeOffset; Plus[Axis]+=GradientProbeOffset; const double DMinus=Shape.detailSampleAt( {Minus[0],Minus[1],Minus[2]}).displacement; const double DPlus=Shape.detailSampleAt( {Plus[0],Plus[1],Plus[2]}).displacement; const double Gradient=(DPlus-DMinus)/(2.0*GradientProbeOffset); DetailGradientSquared+=Gradient*Gradient; } const double DetailGradient=std::sqrt(DetailGradientSquared); DetailGradientAtVertex=DetailGradient; ++Result.DetailGradientSamples; Result.MaximumDetailGradient=std::max( Result.MaximumDetailGradient,DetailGradient); if(DetailGradient>0.55)++Result.DetailGradientOverLimit; const double DetailDisplacement=std::abs(DetailSample.displacement); ++Result.DetailDisplacementSamples; Result.MaximumDetailDisplacement=std::max( Result.MaximumDetailDisplacement,DetailDisplacement); const std::array DetailKey{ static_cast(std::floor((P[0]-Origin.X)/8.0)), static_cast(std::floor((P[1]-Origin.Y)/8.0)), static_cast(std::floor((P[2]-Origin.Z)/8.0))}; FDetailDisplacementBlock& DetailBlock=DetailDisplacementBlocks[DetailKey]; ++DetailBlock.Vertices; DetailBlock.MaximumGradient=std::max(DetailBlock.MaximumGradient,DetailGradientAtVertex); if(DetailDisplacement>0.65) { ++DetailBlock.HighVertices; if(DetailDisplacement>DetailBlock.Maximum) { DetailBlock.Maximum=DetailDisplacement; DetailBlock.Position={P[0],P[1],P[2]}; } ++Result.HighDetailDisplacementSamples; } } } double Grid[3];int32 VariableAxis=-1; for(int32 Axis=0;Axis<3;++Axis) { Grid[Axis]=(P[Axis]-(&Origin.X)[Axis])/Step; if(std::abs(Grid[Axis]-std::round(Grid[Axis]))>0.003) { if(VariableAxis>=0){VariableAxis=-2;break;} VariableAxis=Axis; } } if(VariableAxis<0)continue; double Fraction=Grid[VariableAxis]-std::floor(Grid[VariableAxis]); if(Fraction<0.003||Fraction>0.997)continue; ++Result.EdgeVertices; const int32 CoarseBin=std::clamp(static_cast(Fraction*16.0),0,15); const int32 PreciseBin=std::clamp(static_cast(std::lround(Fraction*256.0)),0,255); ++Result.OffsetHistogram[CoarseBin]; if(CoarseBin==7||CoarseBin==8)++Result.MidpointVertices; double EdgeA[3],EdgeB[3]; for(int32 Axis=0;Axis<3;++Axis) { const int32 Cell=static_cast(std::floor(Grid[Axis])); EdgeA[Axis]=(&Origin.X)[Axis]+Cell*Step; EdgeB[Axis]=EdgeA[Axis]; } EdgeB[VariableAxis]+=Step; const double D0=Shape.densityAt({EdgeA[0],EdgeA[1],EdgeA[2]}); const double D1=Shape.densityAt({EdgeB[0],EdgeB[1],EdgeB[2]}); const double ExactD0=Shape.unclampedDensityAt( {EdgeA[0]+0.013,EdgeA[1]+0.013,EdgeA[2]+0.013}); const double ExactD1=Shape.unclampedDensityAt( {EdgeB[0]+0.013,EdgeB[1]+0.013,EdgeB[2]+0.013}); const double ExactDenominator=ExactD1-ExactD0; ++Result.FieldEdgeChecks; if(std::abs(D0)>127.0/256.0||std::abs(D1)>127.0/256.0) ++Result.OldInt8RangeEdges; const bool bExactCrossing=(ExactD0<0.0&&ExactD1>0.0) ||(ExactD0>0.0&&ExactD1<0.0); double AnalyticShift=0.0; if(bExactCrossing&&std::abs(ExactDenominator)>1.0e-9) { const double ExactT=std::clamp(-ExactD0/ExactDenominator,0.0,1.0); AnalyticShift=std::abs(Fraction-ExactT)*Step; Result.SumAnalyticEdgeShiftVoxels+=AnalyticShift; if(AnalyticShift>Result.MaximumAnalyticEdgeShiftVoxels) { Result.MaximumAnalyticEdgeShiftVoxels=AnalyticShift; Result.WorstShiftPosition={P[0],P[1],P[2]}; Result.WorstShiftFraction=Fraction;Result.WorstShiftD0=D0; Result.WorstShiftD1=D1;Result.WorstShiftExactD0=ExactD0; Result.WorstShiftExactD1=ExactD1;Result.WorstShiftAxis=VariableAxis; } } else ++Result.AnalyticCrossingMisses; if(Tile.Key.Level==0&&Step==1&&bExactCrossing &&Fraction>=0.375&&Fraction<=0.625) { const double MidExact=Shape.unclampedDensityAt({ (EdgeA[0]+EdgeB[0])*0.5+0.013, (EdgeA[1]+EdgeB[1])*0.5+0.013, (EdgeA[2]+EdgeB[2])*0.5+0.013}); double CurveRootT=0.5; if(std::abs(MidExact)>1.0e-8) { if((MidExact<0.0)==(ExactD0<0.0)) { const double Denominator=ExactD1-MidExact; if(std::abs(Denominator)>1.0e-9) CurveRootT=0.5+0.5*std::clamp(-MidExact/Denominator,0.0,1.0); } else { const double Denominator=MidExact-ExactD0; if(std::abs(Denominator)>1.0e-9) CurveRootT=0.5*std::clamp(-ExactD0/Denominator,0.0,1.0); } } const double CurveError=std::abs(Fraction-CurveRootT); ++Result.CurvedEdgeChecks; Result.MaximumCurvedEdgeRootError=std::max( Result.MaximumCurvedEdgeRootError,CurveError); FBlockKey RootKey{};RootKey[0]=VariableAxis; for(int32 Axis=0;Axis<3;++Axis) RootKey[Axis+1]=static_cast(std::floor( (P[Axis]-(&Origin.X)[Axis])/8.0)); FCurvedEdgeRootBlock& RootBlock=CurvedEdgeRootBlocks[RootKey]; ++RootBlock.Vertices; if(CurveError>0.08) { ++RootBlock.BadVertices; if(CurveError>RootBlock.MaximumError) { RootBlock.MaximumError=CurveError; RootBlock.Position={P[0],P[1],P[2]}; } ++Result.CurvedEdgeRootBadVertices; } } const double SourceResidual=std::abs(Shape.unclampedDensityAt({P[0],P[1],P[2]})); if(Tile.Key.Level==0&&Tile.Key.Coord.X==1 &&Tile.Key.Coord.Y==-16&&Tile.Key.Coord.Z==-3) { ++RayTileResidualSamples; RayTileResidualSum+=SourceResidual; if(SourceResidual>0.1)++RayTileResidualGt01; if(SourceResidual>0.25)++RayTileResidualGt025; if(SourceResidual>0.5)++RayTileResidualGt05; if(SourceResidual>RayTileResidualMaximum) { RayTileResidualMaximum=SourceResidual; RayTileResidualMaximumPosition={P[0],P[1],P[2]}; } } Result.SumAbsSourceResidual+=SourceResidual; if(SourceResidual>Result.MaximumAbsSourceResidual) { Result.MaximumAbsSourceResidual=SourceResidual; Result.WorstResidualPosition={P[0],P[1],P[2]}; } const double H=0.5; const double GX=Shape.unclampedDensityAt({P[0]+H+0.013,P[1]+0.013,P[2]+0.013}) -Shape.unclampedDensityAt({P[0]-H+0.013,P[1]+0.013,P[2]+0.013}); const double GY=Shape.unclampedDensityAt({P[0]+0.013,P[1]+H+0.013,P[2]+0.013}) -Shape.unclampedDensityAt({P[0]+0.013,P[1]-H+0.013,P[2]+0.013}); const double GZ=Shape.unclampedDensityAt({P[0]+0.013,P[1]+0.013,P[2]+H+0.013}) -Shape.unclampedDensityAt({P[0]+0.013,P[1]+0.013,P[2]-H+0.013}); const double GL=std::sqrt(GX*GX+GY*GY+GZ*GZ); double NormalAgreement=1.0; if(Tile.Key.Level==0&&GL>1.0e-8) { const auto& N=Tile.Vertices[I].Normal; NormalAgreement=std::clamp((N[0]*GX+N[1]*GY+N[2]*GZ)/GL,-1.0,1.0); ++Result.NormalChecks;Result.SumNormalAgreement+=NormalAgreement; Result.MinimumNormalAgreement=std::min(Result.MinimumNormalAgreement,NormalAgreement); } FBlockKey Key{};Key[0]=VariableAxis; for(int32 Axis=0;Axis<3;++Axis) Key[Axis+1]=static_cast(std::floor((P[Axis]-(&Origin.X)[Axis])/8.0)); if(Tile.Key.Level==0&&GL>1.0e-8) { FNormalBlock& NormalBlock=NormalBlocks[Key]; ++NormalBlock.Vertices; if(NormalAgreement0.5; if(bBadFieldEdge) { ++FieldBlock.BadVertices; if(FieldBlock.BadVertices==1)FieldBlock.Position={P[0],P[1],P[2]}; } FGradientFallbackBlock& FallbackBlock=GradientFallbackBlocks[Key]; ++FallbackBlock.Vertices; uint64 VertexFallbackSamples=0; for(int32 Endpoint=0;Endpoint<2;++Endpoint) { const double* EdgePoint=Endpoint?EdgeB:EdgeA; for(int32 Axis=0;Axis<3;++Axis) for(int32 Side=-1;Side<=1;Side+=2) { double Probe[3]={EdgePoint[0],EdgePoint[1],EdgePoint[2]}; Probe[Axis]+=Side; const double Packed=Shape.densityAt({Probe[0],Probe[1],Probe[2]}); if(std::abs(std::abs(Packed)-4.125)>0.001)continue; double ExactProbe[3]={Probe[0]+0.013,Probe[1]+0.013,Probe[2]+0.013}; const double Exact=Shape.unclampedDensityAt( {ExactProbe[0],ExactProbe[1],ExactProbe[2]}); const double Error=std::abs(Packed-Exact); if(Error<=0.25)continue; ++VertexFallbackSamples; FallbackBlock.MaximumError=std::max(FallbackBlock.MaximumError,Error); } } if(VertexFallbackSamples>0&&NormalAgreement<0.98) { ++FallbackBlock.BadVertices; FallbackBlock.BadSamples+=VertexFallbackSamples; if(FallbackBlock.BadVertices==1)FallbackBlock.Position={P[0],P[1],P[2]}; } } FirstPositionByBlock.try_emplace(Key,std::array{P[0],P[1],P[2]}); const auto& Normal=Tile.Vertices[I].Normal; FirstNormalByBlock.try_emplace(Key,std::array{Normal[0],Normal[1],Normal[2]}); ++OffsetBlocks[Key][PreciseBin]; } struct FHighDetailBlock {std::array Key{};uint64 Vertices=0;double Maximum=0.0,MaximumGradient=0.0; std::array Position{};}; std::vector HighDetailBlocks; for(const auto& [Key,Block]:DetailDisplacementBlocks) { if(Block.Vertices<12||Block.HighVertices<6 ||static_cast(Block.HighVertices)/Block.Vertices<0.25)continue; HighDetailBlocks.push_back({Key,Block.HighVertices,Block.Maximum,Block.MaximumGradient,Block.Position}); } std::vector HighDetailVisited(HighDetailBlocks.size(),0); for(size_t I=0;I Pending{I};HighDetailVisited[I]=1; uint64 BlockCount=0,VertexCountInPatch=0;double Maximum=0.0,MaximumGradient=0.0; size_t Representative=I; while(!Pending.empty()) { const size_t Current=Pending.back();Pending.pop_back(); const FHighDetailBlock& A=HighDetailBlocks[Current]; ++BlockCount;VertexCountInPatch+=A.Vertices; MaximumGradient=std::max(MaximumGradient,A.MaximumGradient); if(A.Maximum>Maximum){Maximum=A.Maximum;Representative=Current;} for(size_t J=0;J(BlockCount), static_cast(VertexCountInPatch),Maximum,MaximumGradient, Sample.Position[0],Sample.Position[1],Sample.Position[2]); } } struct FBadFieldBlock {FBlockKey Key{};uint64 Vertices=0,BadVertices=0;double Share=0.0,MaximumShift=0.0, MaximumResidual=0.0;std::array Position{};}; std::vector BadFieldBlocks; for(const auto& [Key,Block]:FieldBlocks) { if(Block.Vertices<12||Block.BadVertices<6)continue; const double Share=static_cast(Block.BadVertices)/Block.Vertices; if(Share<0.25)continue; BadFieldBlocks.push_back({Key,Block.Vertices,Block.BadVertices,Share, Block.MaximumShift,Block.MaximumResidual,Block.Position}); } std::vector BadFieldVisited(BadFieldBlocks.size(),0); for(size_t I=0;I Pending{I};BadFieldVisited[I]=1; uint64 BlockCount=0,BadVertexCount=0;double MaxShift=0.0,MaxResidual=0.0; size_t Representative=I; while(!Pending.empty()) { const size_t Current=Pending.back();Pending.pop_back(); const FBadFieldBlock& A=BadFieldBlocks[Current]; ++BlockCount;BadVertexCount+=A.BadVertices; MaxShift=std::max(MaxShift,A.MaximumShift); MaxResidual=std::max(MaxResidual,A.MaximumResidual); if(A.MaximumShift>=MaxShift||A.MaximumResidual>=MaxResidual)Representative=Current; for(size_t J=0;J(BlockCount), static_cast(BadVertexCount),MaxShift,MaxResidual, Sample.Position[0],Sample.Position[1],Sample.Position[2]); } } struct FBadGradientFallbackBlock {FBlockKey Key{};uint64 Vertices=0,BadVertices=0,BadSamples=0; double MaximumError=0.0;std::array Position{};}; std::vector BadGradientFallbackBlocks; for(const auto& [Key,Block]:GradientFallbackBlocks) { if(Block.Vertices<12||Block.BadVertices<6)continue; if(static_cast(Block.BadVertices)/Block.Vertices<0.25)continue; BadGradientFallbackBlocks.push_back({Key,Block.Vertices,Block.BadVertices, Block.BadSamples,Block.MaximumError,Block.Position}); } std::vector GradientFallbackVisited(BadGradientFallbackBlocks.size(),0); for(size_t I=0;I Pending{I};GradientFallbackVisited[I]=1; uint64 BlockCount=0,BadVertexCount=0,BadSamples=0;double MaximumError=0.0; size_t Representative=I; while(!Pending.empty()) { const size_t Current=Pending.back();Pending.pop_back(); const FBadGradientFallbackBlock& A=BadGradientFallbackBlocks[Current]; ++BlockCount;BadVertexCount+=A.BadVertices;BadSamples+=A.BadSamples; MaximumError=std::max(MaximumError,A.MaximumError); if(A.MaximumError>=MaximumError)Representative=Current; for(size_t J=0;J(BlockCount), static_cast(BadVertexCount), static_cast(BadSamples),MaximumError, Sample.Position[0],Sample.Position[1],Sample.Position[2]); } } struct FBadNormalBlock {FBlockKey Key{};uint64 Vertices=0,BadVertices=0;double MinimumAgreement=1.0; std::array Position{},MeshNormal{};}; std::vector BadNormalBlocks; for(const auto& [Key,Block]:NormalBlocks) { if(Block.Vertices<12||Block.BadVertices<6)continue; if(static_cast(Block.BadVertices)/Block.Vertices<0.25)continue; BadNormalBlocks.push_back({Key,Block.Vertices,Block.BadVertices, Block.MinimumAgreement,Block.Position,Block.MeshNormal}); } std::vector BadNormalVisited(BadNormalBlocks.size(),0); for(size_t I=0;I Pending{I};BadNormalVisited[I]=1; uint64 BlockCount=0,BadVertexCount=0;double MinAgreement=1.0;size_t Representative=I; while(!Pending.empty()) { const size_t Current=Pending.back();Pending.pop_back(); const FBadNormalBlock& A=BadNormalBlocks[Current]; ++BlockCount;BadVertexCount+=A.BadVertices; MinAgreement=std::min(MinAgreement,A.MinimumAgreement); if(A.MinimumAgreement(BlockCount), static_cast(BadVertexCount),MinAgreement, Sample.Position[0],Sample.Position[1],Sample.Position[2]); double EdgeA[3],EdgeB[3]; for(int32 Axis=0;Axis<3;++Axis) { EdgeA[Axis]=(&Origin.X)[Axis] +std::floor((Sample.Position[Axis]-(&Origin.X)[Axis])/Step)*Step; EdgeB[Axis]=EdgeA[Axis]; } EdgeB[Sample.Key[0]]+=Step; double GradPacked[2][3]{},GradExact[2][3]{}; for(int32 Endpoint=0;Endpoint<2;++Endpoint) { const double* P=Endpoint?EdgeB:EdgeA; for(int32 Axis=0;Axis<3;++Axis) { double Minus[3]={P[0],P[1],P[2]},Plus[3]={P[0],P[1],P[2]}; Minus[Axis]-=1.0;Plus[Axis]+=1.0; GradPacked[Endpoint][Axis]=Shape.densityAt({Plus[0],Plus[1],Plus[2]}) -Shape.densityAt({Minus[0],Minus[1],Minus[2]}); for(int32 A=0;A<3;++A){Minus[A]+=0.013;Plus[A]+=0.013;} GradExact[Endpoint][Axis]=Shape.unclampedDensityAt( {Plus[0],Plus[1],Plus[2]}) -Shape.unclampedDensityAt({Minus[0],Minus[1],Minus[2]}); } } const double T=std::clamp(Sample.Position[Sample.Key[0]]-EdgeA[Sample.Key[0]],0.0,1.0); double PackedInterpolated[3]{},ExactInterpolated[3]{}; for(int32 Axis=0;Axis<3;++Axis) { PackedInterpolated[Axis]=GradPacked[0][Axis]+T*(GradPacked[1][Axis]-GradPacked[0][Axis]); ExactInterpolated[Axis]=GradExact[0][Axis]+T*(GradExact[1][Axis]-GradExact[0][Axis]); } const auto NormalDot=[](const double A[3],const double B[3]) { const double AL=std::sqrt(A[0]*A[0]+A[1]*A[1]+A[2]*A[2]); const double BL=std::sqrt(B[0]*B[0]+B[1]*B[1]+B[2]*B[2]); return AL>1.0e-10&&BL>1.0e-10 ?(A[0]*B[0]+A[1]*B[1]+A[2]*B[2])/(AL*BL):0.0; }; std::printf("[MeshNormalProbe] t=%.3f edge_axis=%d mesh=(%.3f,%.3f,%.3f) packed_grid=(%.3f,%.3f,%.3f) exact_grid=(%.3f,%.3f,%.3f) packed_dot=%.3f exact_dot=%.3f endpoints=(%.0f,%.0f,%.0f)->(%.0f,%.0f,%.0f)\n", T,Sample.Key[0],Sample.MeshNormal[0],Sample.MeshNormal[1],Sample.MeshNormal[2], PackedInterpolated[0],PackedInterpolated[1],PackedInterpolated[2], ExactInterpolated[0],ExactInterpolated[1],ExactInterpolated[2], NormalDot(Sample.MeshNormal.data(),PackedInterpolated), NormalDot(Sample.MeshNormal.data(),ExactInterpolated), EdgeA[0],EdgeA[1],EdgeA[2],EdgeB[0],EdgeB[1],EdgeB[2]); for(int32 Endpoint=0;Endpoint<2;++Endpoint) for(int32 Axis=0;Axis<3;++Axis) { const double* P=Endpoint?EdgeB:EdgeA; for(int32 Side=-1;Side<=1;Side+=2) { double Q[3]={P[0],P[1],P[2]};Q[Axis]+=Side; const double Packed=Shape.densityAt({Q[0],Q[1],Q[2]}); Q[0]+=0.013;Q[1]+=0.013;Q[2]+=0.013; const double Exact=Shape.unclampedDensityAt({Q[0],Q[1],Q[2]}); if(std::abs(Packed-Exact)>0.02) std::printf("[MeshNormalProbeNode] endpoint=%d axis=%d side=%d packed=%.4f exact=%.4f delta=%.4f\n", Endpoint,Axis,Side,Packed,Exact,Packed-Exact); } } } } if(Tile.Key.Level==0&&Tile.Key.Coord.X==1 &&Tile.Key.Coord.Y==-16&&Tile.Key.Coord.Z==-3) { struct FConcentratedBlock {FBlockKey Key{};uint64 Count=0;double TopOne=0.0,TopThree=0.0; std::array Bins{};std::array Position{};}; std::vector ConcentratedBlocks; for(const auto& [Key,Bins]:OffsetBlocks) { const uint64 Count=std::accumulate(Bins.begin(),Bins.end(),uint64{0}); if(Count<12)continue; std::array Order{}; std::iota(Order.begin(),Order.end(),0); std::partial_sort(Order.begin(),Order.begin()+3,Order.end(), [&](int32 A,int32 B){return Bins[A]>Bins[B];}); const uint64 TopThree=Bins[Order[0]]+Bins[Order[1]]+Bins[Order[2]]; ConcentratedBlocks.push_back({Key,Count, static_cast(Bins[Order[0]])/Count, static_cast(TopThree)/Count, {Order[0],Order[1],Order[2]},FirstPositionByBlock[Key]}); } std::sort(ConcentratedBlocks.begin(),ConcentratedBlocks.end(), [](const auto& A,const auto& B){return A.TopThree>B.TopThree;}); for(size_t I=0;I(8,ConcentratedBlocks.size());++I) { const auto& B=ConcentratedBlocks[I]; std::printf("[MeshOffsetConcentration] tile=(1,-16,-3) axis=%d block=(%d,%d,%d) vertices=%llu top1=%.3f top3=%.3f bins=(%d,%d,%d) sample=(%.3f,%.3f,%.3f)\n", B.Key[0],B.Key[1],B.Key[2],B.Key[3], static_cast(B.Count),B.TopOne,B.TopThree, B.Bins[0],B.Bins[1],B.Bins[2], B.Position[0],B.Position[1],B.Position[2]); } } struct FRepeatBlock {FBlockKey Key{};int32 Bin=0;uint64 Count=0;double Share=0.0; std::array Position{},Normal{};}; std::vector RepeatBlocks; for(const auto& [Key,Bins]:OffsetBlocks) { const uint64 Count=std::accumulate(Bins.begin(),Bins.end(),uint64{0}); if(Count<12)continue; const auto Best=std::max_element(Bins.begin(),Bins.end()); const int32 Bin=static_cast(Best-Bins.begin()); const double Share=static_cast(*Best)/Count; if(Bin<80||Bin>176||Share<0.75)continue; RepeatBlocks.push_back({Key,Bin,Count,Share,FirstPositionByBlock[Key],FirstNormalByBlock[Key]}); } std::vector Visited(RepeatBlocks.size(),0); for(size_t I=0;I Pending{I};Visited[I]=1; uint64 BlockCount=0,VertexCountInPatch=0;double Dominance=0.0; while(!Pending.empty()) { const size_t Current=Pending.back();Pending.pop_back(); const FRepeatBlock& A=RepeatBlocks[Current]; ++BlockCount;VertexCountInPatch+=A.Count;Dominance=std::max(Dominance,A.Share); for(size_t J=0;J1)continue; int32 Manhattan=0; for(int32 Axis=1;Axis<4;++Axis) Manhattan+=std::abs(A.Key[Axis]-RepeatBlocks[J].Key[Axis]); if(Manhattan==1){Visited[J]=1;Pending.push_back(J);} } } if(BlockCount<3||VertexCountInPatch<48)continue; ++Result.RepeatedOffsetPatches; Result.MaximumPatchDominance=std::max(Result.MaximumPatchDominance,Dominance); if(bPrintPatches&&Result.RepeatedOffsetPatches<=8) { const auto& P=RepeatBlocks[I].Position;const int32 Axis=RepeatBlocks[I].Key[0]; double EdgeA[3],EdgeB[3]; for(int32 A=0;A<3;++A) { const int32 Cell=static_cast(std::floor((P[A]-(&Origin.X)[A])/Step)); EdgeA[A]=(&Origin.X)[A]+Cell*Step;EdgeB[A]=EdgeA[A]; } EdgeB[Axis]+=Step; const double D0=Shape.densityAt({EdgeA[0],EdgeA[1],EdgeA[2]}); const double D1=Shape.densityAt({EdgeB[0],EdgeB[1],EdgeB[2]}); const double ExactD0=Shape.densityAt({EdgeA[0]+0.013,EdgeA[1]+0.013,EdgeA[2]+0.013}); const double ExactD1=Shape.densityAt({EdgeB[0]+0.013,EdgeB[1]+0.013,EdgeB[2]+0.013}); const double InterpolatedT=std::abs(D1-D0)>1.0e-9 ?std::clamp(-D0/(D1-D0),0.0,1.0):0.5; const double SourceDensity=Shape.densityAt({P[0],P[1],P[2]}); const auto& N=RepeatBlocks[I].Normal; const double PlusNormal=Shape.densityAt({P[0]+N[0],P[1]+N[1],P[2]+N[2]}); const double MinusNormal=Shape.densityAt({P[0]-N[0],P[1]-N[1],P[2]-N[2]}); std::printf("[MeshLatticePatch] level=%d tile=(%d,%d,%d) connected_8vox_blocks=%llu edge_vertices=%llu dominant_share=%.3f midpoint_bin_cluster=1 axis=%d sample=(%.3f,%.3f,%.3f) offset=%.4f normal=(%.3f,%.3f,%.3f) endpoint_density=(%.4f,%.4f) analytic_probe=(%.4f,%.4f) predicted_t=%.4f source_density=%.4f normal_probe=(plus1=%.4f,minus1=%.4f)\n", Tile.Key.Level,Tile.Key.Coord.X,Tile.Key.Coord.Y,Tile.Key.Coord.Z, static_cast(BlockCount), static_cast(VertexCountInPatch),Dominance,Axis, P[0],P[1],P[2],(P[Axis]-EdgeA[Axis])/Step,N[0],N[1],N[2],D0,D1, ExactD0,ExactD1,InterpolatedT,SourceDensity,PlusNormal,MinusNormal); } } const size_t TriangleCount=Tile.Indices.size()/3; for(size_t T=0;T=VertexCount||B>=VertexCount||C>=VertexCount)continue; if(A0.125)++RayTileInteriorGt0125; if(Residual>0.25)++RayTileInteriorGt025; if(Residual>0.5)++RayTileInteriorGt05; if(Residual>1.0)++RayTileInteriorGt1; if(Residual>RayTileInteriorResidualMaximum) { RayTileInteriorResidualMaximum=Residual; RayTileInteriorMaximumPosition={Sample[0],Sample[1],Sample[2]}; } } } continue; } const uint8 SkirtFaces=T(PA[0])+PB[0]+PC[0])*4.0/3.0, (static_cast(PA[1])+PB[1]+PC[1])*4.0/3.0, (static_cast(PA[2])+PB[2]+PC[2])*4.0/3.0}; const double Density=Shape.densityAt(Center); double AlternativeCenter[3]={0.0,0.0,0.0}; const uint32 TriangleIndices[3]={A,B,C}; for(uint32 Index:TriangleIndices) for(int32 Axis=0;Axis<3;++Axis) { double Position=Tile.Vertices[Index].Position[Axis]; if(Index>=SurfaceVertices) Position+=2.0*SkirtDepthMeters*Tile.Vertices[Index].Normal[Axis]; AlternativeCenter[Axis]+=Position*4.0/3.0; } const double AlternativeDensity=Shape.densityAt({ AlternativeCenter[0],AlternativeCenter[1],AlternativeCenter[2]}); double Normal[3]={0.0,0.0,0.0}; for(uint32 Index:TriangleIndices)if(Index>=SurfaceVertices) for(int32 Axis=0;Axis<3;++Axis)Normal[Axis]+=Tile.Vertices[Index].Normal[Axis]; const double NormalLength=std::sqrt(Normal[0]*Normal[0]+Normal[1]*Normal[1]+Normal[2]*Normal[2]); if(NormalLength>1.0e-8)for(double& Value:Normal)Value/=NormalLength; const double Inward1=Shape.densityAt({Center.x-Normal[0],Center.y-Normal[1],Center.z-Normal[2]}); const double Inward2=Shape.densityAt({Center.x-Normal[0]*2.0,Center.y-Normal[1]*2.0,Center.z-Normal[2]*2.0}); double MaximumProbeDensity=Density; const double ProbeWeights[10][3]={ {1.0,0.0,0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}, {1.0/3.0,1.0/3.0,1.0/3.0}, {0.5,0.5,0.0},{0.0,0.5,0.5},{0.5,0.0,0.5}, {0.75,0.125,0.125},{0.125,0.75,0.125},{0.125,0.125,0.75}}; for(const auto& Weights:ProbeWeights) { const VoxelForgeCore::Vec3d Probe{ PA[0]*Weights[0]+PB[0]*Weights[1]+PC[0]*Weights[2], PA[1]*Weights[0]+PB[1]*Weights[1]+PC[1]*Weights[2], PA[2]*Weights[0]+PB[2]*Weights[1]+PC[2]*Weights[2]}; MaximumProbeDensity=std::max(MaximumProbeDensity,static_cast( Shape.densityAt({Probe.x*4.0,Probe.y*4.0,Probe.z*4.0}))); } if(MaximumProbeDensity>0.25) { ++Result.ExposedSkirtTriangles; Result.MaximumAirSkirtDensity=std::max( Result.MaximumAirSkirtDensity,MaximumProbeDensity); if(AlternativeDensity<-0.25)++Result.ReverseSideSolidSkirtTriangles; if(bPrintSkirts&&Result.ExposedSkirtTriangles<=8) std::printf("[ExposedTileSkirt] level=%d tile=(%d,%d,%d) center=(%.2f,%.2f,%.2f) center_density=%.3f max_probe_density=%.3f reverse_density=%.3f inward=(%.3f,%.3f) normal=(%.3f,%.3f,%.3f)\n", Tile.Key.Level,Tile.Key.Coord.X,Tile.Key.Coord.Y,Tile.Key.Coord.Z, Center.x,Center.y,Center.z,Density,MaximumProbeDensity, AlternativeDensity,Inward1,Inward2, Normal[0],Normal[1],Normal[2]); } } if(Tile.Key.Level==0&&Tile.Key.Coord.X==1 &&Tile.Key.Coord.Y==-16&&Tile.Key.Coord.Z==-3) { std::printf("[MeshRayTileResidual] tile=(1,-16,-3) vertices=%llu mean=%.4f max=%.4f gt0.1=%llu gt0.25=%llu gt0.5=%llu max_vertex=(%.3f,%.3f,%.3f)\n", static_cast(RayTileResidualSamples), RayTileResidualSamples?RayTileResidualSum/RayTileResidualSamples:0.0, RayTileResidualMaximum, static_cast(RayTileResidualGt01), static_cast(RayTileResidualGt025), static_cast(RayTileResidualGt05), RayTileResidualMaximumPosition[0],RayTileResidualMaximumPosition[1], RayTileResidualMaximumPosition[2]); std::printf("[MeshRayTileInteriorResidual] tile=(1,-16,-3) samples=%llu mean=%.4f max=%.4f gt0.125=%llu gt0.25=%llu gt0.5=%llu gt1=%llu max_probe=(%.3f,%.3f,%.3f)\n", static_cast(RayTileInteriorSamples), RayTileInteriorSamples?RayTileInteriorResidualSum/RayTileInteriorSamples:0.0, RayTileInteriorResidualMaximum, static_cast(RayTileInteriorGt0125), static_cast(RayTileInteriorGt025), static_cast(RayTileInteriorGt05), static_cast(RayTileInteriorGt1), RayTileInteriorMaximumPosition[0],RayTileInteriorMaximumPosition[1], RayTileInteriorMaximumPosition[2]); } struct FBadCurvedEdgeRootBlock {FBlockKey Key{};uint64 Vertices=0,BadVertices=0;double Share=0.0,MaximumError=0.0; std::array Position{};}; std::vector BadCurvedEdgeRootBlocks; for(const auto& [Key,Block]:CurvedEdgeRootBlocks) { if(Block.Vertices<12||Block.BadVertices<6)continue; const double Share=static_cast(Block.BadVertices)/Block.Vertices; if(Share<0.25)continue; BadCurvedEdgeRootBlocks.push_back({Key,Block.Vertices,Block.BadVertices,Share, Block.MaximumError,Block.Position}); } std::vector CurvedEdgeRootVisited(BadCurvedEdgeRootBlocks.size(),0); for(size_t I=0;I Pending{I};CurvedEdgeRootVisited[I]=1; uint64 BlockCount=0,BadVertexCount=0;double MaximumError=0.0;size_t Representative=I; while(!Pending.empty()) { const size_t Current=Pending.back();Pending.pop_back(); const FBadCurvedEdgeRootBlock& A=BadCurvedEdgeRootBlocks[Current]; ++BlockCount;BadVertexCount+=A.BadVertices; if(A.MaximumError>MaximumError) {MaximumError=A.MaximumError;Representative=Current;} for(size_t J=0;J(BlockCount), static_cast(BadVertexCount),MaximumError, Sample.Position[0],Sample.Position[1],Sample.Position[2]); } } return Result; } FMeshSheetAudit AuditThinMeshSheets(const FStandaloneCpuTile& Tile, const FVector& CameraVoxels,float Yaw,float Pitch,bool bPrintCandidates) { FMeshSheetAudit Result; const size_t VertexCount=Tile.Vertices.size(); if(VertexCount==0||Tile.Indices.size()<3)return Result; std::vector Parent(VertexCount); std::vector Rank(VertexCount,0); std::iota(Parent.begin(),Parent.end(),0u); auto Find=[&](uint32 Value) { uint32 Root=Value; while(Parent[Root]!=Root)Root=Parent[Root]; while(Parent[Value]!=Value) {const uint32 Next=Parent[Value];Parent[Value]=Root;Value=Next;} return Root; }; auto Union=[&](uint32 A,uint32 B) { A=Find(A);B=Find(B);if(A==B)return; if(Rank[A]=VertexCount||B>=VertexCount||C>=VertexCount)continue; Union(A,B);Union(B,C); } struct FComponent { uint64 Triangles=0,Vertices=0; double Min[3]={std::numeric_limits::max(),std::numeric_limits::max(),std::numeric_limits::max()}; double Max[3]={-std::numeric_limits::max(),-std::numeric_limits::max(),-std::numeric_limits::max()}; double Sum[3]={0.0,0.0,0.0}; double Cov[6]={0.0,0.0,0.0,0.0,0.0,0.0}; }; std::vector Components(VertexCount); for(size_t I=0;I(I)); FComponent& C=Components[Root];++C.Vertices; for(int32 A=0;A<3;++A) { const double P=Tile.Vertices[I].Position[A]; C.Min[A]=std::min(C.Min[A],P);C.Max[A]=std::max(C.Max[A],P);C.Sum[A]+=P; } } for(size_t T=0;T=VertexCount||B>=VertexCount||C>=VertexCount)continue; ++Components[Find(A)].Triangles; } for(size_t I=0;I(I)); FComponent& C=Components[Root]; if(C.Vertices==0)continue; const double P[3]={Tile.Vertices[I].Position[0],Tile.Vertices[I].Position[1],Tile.Vertices[I].Position[2]}; const double D[3]={P[0]-C.Sum[0]/C.Vertices,P[1]-C.Sum[1]/C.Vertices,P[2]-C.Sum[2]/C.Vertices}; C.Cov[0]+=D[0]*D[0];C.Cov[1]+=D[1]*D[1];C.Cov[2]+=D[2]*D[2]; C.Cov[3]+=D[0]*D[1];C.Cov[4]+=D[0]*D[2];C.Cov[5]+=D[1]*D[2]; } const double Camera[3]={CameraVoxels.X*0.25,CameraVoxels.Y*0.25,CameraVoxels.Z*0.25}; const double CP=std::cos(Pitch),Forward[3]={std::sin(Yaw)*CP,std::cos(Yaw)*CP,std::sin(Pitch)}; const double Right[3]={std::cos(Yaw),-std::sin(Yaw),0.0}; const double Up[3]={-std::sin(Yaw)*std::sin(Pitch),-std::cos(Yaw)*std::sin(Pitch),std::cos(Pitch)}; for(size_t Root=0;Rootstd::abs(A[P][Q])){P=0;Q=2;} if(std::abs(A[1][2])>std::abs(A[P][Q])){P=1;Q=2;} if(std::abs(A[P][Q])<1.0e-16)break; const double Tau=(A[Q][Q]-A[P][P])/(2.0*A[P][Q]); const double T=std::copysign(1.0,Tau)/(std::abs(Tau)+std::sqrt(1.0+Tau*Tau)); const double Cos=1.0/std::sqrt(1.0+T*T),Sin=T*Cos; const double App=A[P][P],Aqq=A[Q][Q],Apq=A[P][Q]; A[P][P]=App-T*Apq;A[Q][Q]=Aqq+T*Apq;A[P][Q]=A[Q][P]=0.0; for(int32 K=0;K<3;++K)if(K!=P&&K!=Q) { const double Akp=A[K][P],Akq=A[K][Q]; A[K][P]=A[P][K]=Cos*Akp-Sin*Akq; A[K][Q]=A[Q][K]=Sin*Akp+Cos*Akq; } } const double Variance=std::max(0.0,std::min({A[0][0],A[1][1],A[2][2]})/C.Vertices); const double ThicknessVoxels=3.5*std::sqrt(Variance)/0.25; const double Center[3]={C.Sum[0]/C.Vertices,C.Sum[1]/C.Vertices,C.Sum[2]/C.Vertices}; const double Relative[3]={Center[0]-Camera[0],Center[1]-Camera[1],Center[2]-Camera[2]}; const double Depth=Relative[0]*Forward[0]+Relative[1]*Forward[1]+Relative[2]*Forward[2]; const double ScreenX=Relative[0]*Right[0]+Relative[1]*Right[1]+Relative[2]*Right[2]; const double ScreenY=Relative[0]*Up[0]+Relative[1]*Up[1]+Relative[2]*Up[2]; const bool bInView=Depth>0.0&&Depth<=64.0&&std::abs(ScreenX)<0.924*Depth &&std::abs(ScreenY)<0.5774*Depth; if(!bInView)continue; const FIntVector TileOrigin=Tile.Key.OriginVoxels(); const int32 TileMin[3]={TileOrigin.X,TileOrigin.Y,TileOrigin.Z}; const int32 TileMax[3]={TileOrigin.X+Tile.Key.ExtentVoxels(), TileOrigin.Y+Tile.Key.ExtentVoxels(),TileOrigin.Z+Tile.Key.ExtentVoxels()}; bool bTouchesTileBoundary=false; for(int32 Axis=0;Axis<3;++Axis) { const double MinVoxels=C.Min[Axis]*4.0,MaxVoxels=C.Max[Axis]*4.0; bTouchesTileBoundary|=MinVoxels<=TileMin[Axis]+0.5 ||MaxVoxels>=TileMax[Axis]-0.5; } if(bTouchesTileBoundary)++Result.BoundarySmallComponentsInView; else ++Result.SmallComponentsInView; if(bPrintCandidates&&!bTouchesTileBoundary&&Result.SmallComponentsInView<=8) std::printf("[SmallMeshComponent] level=%d tile=(%d,%d,%d) tris=%llu size=(%.2f,%.2f,%.2f) vox pca_thickness=%.3f vox center=(%.2f,%.2f,%.2f)m\n", Tile.Key.Level,Tile.Key.Coord.X,Tile.Key.Coord.Y,Tile.Key.Coord.Z, static_cast(C.Triangles),Extent[0]/0.25,Extent[1]/0.25, Extent[2]/0.25,ThicknessVoxels,Center[0],Center[1],Center[2]); else if(bPrintCandidates&&bTouchesTileBoundary &&Result.BoundarySmallComponentsInView<=8) std::printf("[BoundaryMeshComponent] level=%d tile=(%d,%d,%d) tris=%llu size=(%.2f,%.2f,%.2f) vox pca_thickness=%.3f vox center=(%.2f,%.2f,%.2f)m\n", Tile.Key.Level,Tile.Key.Coord.X,Tile.Key.Coord.Y,Tile.Key.Coord.Z, static_cast(C.Triangles),Extent[0]/0.25,Extent[1]/0.25, Extent[2]/0.25,ThicknessVoxels,Center[0],Center[1],Center[2]); if(ThicknessVoxels>=1.0)continue; ++Result.ThinSheets;Result.MinimumThicknessVoxels=std::min(Result.MinimumThicknessVoxels,ThicknessVoxels); Result.TrianglesInThinSheets+=C.Triangles; if(bPrintCandidates&&Result.ThinSheets==1) std::printf("[ThinMeshSheetCandidate] level=%d tile=(%d,%d,%d) tris=%llu size=(%.2f,%.2f,%.2f) vox pca_thickness=%.3f vox center=(%.2f,%.2f,%.2f)m\n", Tile.Key.Level,Tile.Key.Coord.X,Tile.Key.Coord.Y,Tile.Key.Coord.Z, static_cast(C.Triangles),Extent[0]/0.25,Extent[1]/0.25,Extent[2]/0.25, ThicknessVoxels,Center[0],Center[1],Center[2]); } return Result; } struct FCoarsePanelAudit { uint64 Tiles=0,PlanarOpenComponents=0,OffSurfacePanels=0,Triangles=0; double MaximumSourceErrorVoxels=0.0; }; FCoarsePanelAudit AuditCoarseSurfacePanels(const FStandaloneCpuTile& Tile, const VoxelForgeCore::World& Shape,const VoxelForgeCore::WorldConfiguration& Config, bool bPrintCandidates) { FCoarsePanelAudit Result; const size_t VertexCount=Tile.Vertices.size(); const size_t TriangleCount=Tile.Indices.size()/3; if(Tile.Key.Level<1||VertexCount==0||TriangleCount==0)return Result; std::vector Parent(VertexCount); std::vector Rank(VertexCount,0); std::iota(Parent.begin(),Parent.end(),0u); const auto Find=[&](uint32 Value) { uint32 Root=Value; while(Parent[Root]!=Root)Root=Parent[Root]; while(Parent[Value]!=Value) {const uint32 Next=Parent[Value];Parent[Value]=Root;Value=Next;} return Root; }; const auto Union=[&](uint32 A,uint32 B) { A=Find(A);B=Find(B);if(A==B)return; if(Rank[A]B)std::swap(A,B);return (static_cast(A)<<32)|B;}; std::unordered_map EdgeUse; EdgeUse.reserve(TriangleCount*3/2+1); for(size_t T=0;T=VertexCount||B>=VertexCount||C>=VertexCount)continue; Union(A,B);Union(B,C); for(const auto [U,V]:std::array,3>{{{A,B},{B,C},{C,A}}}) { uint8& Count=EdgeUse[EdgeKey(U,V)]; if(Count<255)++Count; } } struct FComponent { uint64 Triangles=0,InteriorFreeEdges=0,SourceSamples=0,OffSourceSamples=0; double Normal[3]={0,0,0},NormalWeight=0,MaximumSourceError=0; double WorstPosition[3]={0,0,0}; bool bWorstTriangleCentroid=false; }; std::vector Components(VertexCount); for(size_t T=0;T=VertexCount||B>=VertexCount||C>=VertexCount)continue; const uint32 Root=Find(A);FComponent& Stats=Components[Root];++Stats.Triangles; const auto& PA=Tile.Vertices[A].Position;const auto& PB=Tile.Vertices[B].Position; const auto& PC=Tile.Vertices[C].Position; const double U[3]={PB[0]-PA[0],PB[1]-PA[1],PB[2]-PA[2]}; const double V[3]={PC[0]-PA[0],PC[1]-PA[1],PC[2]-PA[2]}; double N[3]={U[1]*V[2]-U[2]*V[1],U[2]*V[0]-U[0]*V[2],U[0]*V[1]-U[1]*V[0]}; const double Area2=std::sqrt(N[0]*N[0]+N[1]*N[1]+N[2]*N[2]); if(Area2>1.0e-12) { for(int32 Axis=0;Axis<3;++Axis)Stats.Normal[Axis]+=N[Axis]/Area2*Area2; Stats.NormalWeight+=Area2; } } const FIntVector Origin=Tile.Key.OriginVoxels(); const double TileMin[3]={static_cast(Origin.X),static_cast(Origin.Y),static_cast(Origin.Z)}; const double TileMax[3]={TileMin[0]+Tile.Key.ExtentVoxels(),TileMin[1]+Tile.Key.ExtentVoxels(),TileMin[2]+Tile.Key.ExtentVoxels()}; const auto IsTileBoundaryEdge=[&](uint32 A,uint32 B) { for(int32 Axis=0;Axis<3;++Axis) { const double PA=Tile.Vertices[A].Position[Axis]*4.0; const double PB=Tile.Vertices[B].Position[Axis]*4.0; if((std::abs(PA-TileMin[Axis])<0.75&&std::abs(PB-TileMin[Axis])<0.75) ||(std::abs(PA-TileMax[Axis])<0.75&&std::abs(PB-TileMax[Axis])<0.75))return true; } return false; }; for(const auto& [Key,Count]:EdgeUse) { if(Count!=1)continue; const uint32 A=static_cast(Key>>32),B=static_cast(Key); if(A>=VertexCount||B>=VertexCount||IsTileBoundaryEdge(A,B))continue; ++Components[Find(A)].InteriorFreeEdges; } const int32 Extent=Tile.Key.ExtentVoxels(); const int32 Cells=Tile.Key.Level Candidate(VertexCount,0); for(size_t Root=0;Root256||Stats.InteriorFreeEdges==0||Stats.NormalWeight<=0.0)continue; const double NormalLength=std::sqrt(Stats.Normal[0]*Stats.Normal[0] +Stats.Normal[1]*Stats.Normal[1]+Stats.Normal[2]*Stats.Normal[2]); const double Coherence=NormalLength/Stats.NormalWeight; if(Coherence<0.995)continue; Candidate[Root]=1;++Result.PlanarOpenComponents; } if(Result.PlanarOpenComponents==0)return Result; for(size_t Vertex=0;Vertex(Vertex)); if(!Candidate[Root])continue; const auto& P=Tile.Vertices[Vertex].Position; const double Error=std::abs(Shape.densityAt({P[0]*4.0,P[1]*4.0,P[2]*4.0})); FComponent& Stats=Components[Root];++Stats.SourceSamples; if(Error>Stats.MaximumSourceError) { Stats.MaximumSourceError=Error; std::copy_n(P,3,Stats.WorstPosition); Stats.bWorstTriangleCentroid=false; } if(Error>ResidualLimit)++Stats.OffSourceSamples; } for(size_t T=0;T=VertexCount||B>=VertexCount||C>=VertexCount)continue; const uint32 Root=Find(A);if(!Candidate[Root])continue; const auto& PA=Tile.Vertices[A].Position;const auto& PB=Tile.Vertices[B].Position; const auto& PC=Tile.Vertices[C].Position; const double Error=std::abs(Shape.densityAt({(PA[0]+PB[0]+PC[0])*4.0/3.0, (PA[1]+PB[1]+PC[1])*4.0/3.0,(PA[2]+PB[2]+PC[2])*4.0/3.0})); FComponent& Stats=Components[Root];++Stats.SourceSamples; if(Error>Stats.MaximumSourceError) { Stats.MaximumSourceError=Error; Stats.WorstPosition[0]=(PA[0]+PB[0]+PC[0])/3.0; Stats.WorstPosition[1]=(PA[1]+PB[1]+PC[1])/3.0; Stats.WorstPosition[2]=(PA[2]+PB[2]+PC[2])/3.0; Stats.bWorstTriangleCentroid=true; } if(Error>ResidualLimit)++Stats.OffSourceSamples; } for(size_t Root=0;Root(Stats.OffSourceSamples)/Stats.SourceSamples; Result.MaximumSourceErrorVoxels=std::max(Result.MaximumSourceErrorVoxels,Stats.MaximumSourceError); if(OffShare<0.25)continue; ++Result.OffSurfacePanels;Result.Triangles+=Stats.Triangles; if(bPrintCandidates&&Result.OffSurfacePanels<=8) std::printf("[CoarsePanelCandidate] lod=%d tile=(%d,%d,%d) triangles=%llu interior_free_edges=%llu source_error=%.3f vox off_share=%.1f%% limit=%.3f vox worst=(%.2f,%.2f,%.2f)m sample=%s\n", Tile.Key.Level,Tile.Key.Coord.X,Tile.Key.Coord.Y,Tile.Key.Coord.Z, static_cast(Stats.Triangles), static_cast(Stats.InteriorFreeEdges),Stats.MaximumSourceError, OffShare*100.0,ResidualLimit, Stats.WorstPosition[0],Stats.WorstPosition[1],Stats.WorstPosition[2], Stats.bWorstTriangleCentroid?"centroid":"vertex"); } Result.Tiles=1; return Result; } struct M4 { float M[4][4]{}; }; M4 Identity(){M4 R{};for(int I=0;I<4;++I)R.M[I][I]=1.0f;return R;} M4 Transpose(M4 A){M4 B{};for(int I=0;I<4;++I)for(int J=0;J<4;++J)B.M[I][J]=A.M[J][I];return B;} M4 Perspective(float Fov,float Aspect,float NearZ,float FarZ) { M4 R{};const float Y=1.0f/std::tan(Fov*0.5f); R.M[0][0]=Y/Aspect;R.M[1][1]=Y;R.M[2][2]=FarZ/(FarZ-NearZ); R.M[2][3]=1.0f;R.M[3][2]=-NearZ*FarZ/(FarZ-NearZ);return R; } M4 View(V3 Position,V3 Forward,V3 Right,V3 Up) { M4 R=Identity(); R.M[0][0]=Right.X;R.M[1][0]=Right.Y;R.M[2][0]=Right.Z;R.M[3][0]=-Dot(Right,Position); R.M[0][1]=Up.X;R.M[1][1]=Up.Y;R.M[2][1]=Up.Z;R.M[3][1]=-Dot(Up,Position); R.M[0][2]=Forward.X;R.M[1][2]=Forward.Y;R.M[2][2]=Forward.Z;R.M[3][2]=-Dot(Forward,Position); return R; } struct FGpuVertex { float Position[3]; float Normal[3]; }; struct FConstants { M4 ViewProjection; float Camera[3]; float FogStart; float Forward[3]; float FogEnd; float LightDirection[3]; float Ambient; float Padding[4]; }; constexpr int32 MaxLevels=8; struct FStandaloneBatchKey { int32 Level=0,X=0,Y=0,Z=0; bool operator==(const FStandaloneBatchKey& O)const {return Level==O.Level&&X==O.X&&Y==O.Y&&Z==O.Z;} }; struct FStandaloneBatchKeyHash { size_t operator()(const FStandaloneBatchKey& K)const noexcept { uint64 H=static_cast(K.Level); H=(H*0x9e3779b185ebca87ull)^static_cast(K.X); H=(H*0x9e3779b185ebca87ull)^static_cast(K.Y); H=(H*0x9e3779b185ebca87ull)^static_cast(K.Z); return static_cast(H^(H>>32)); } }; struct FResidentTileMesh { std::vector Vertices; std::vector Indices; std::vector TriangleSkirtFaceMasks; uint8 ActiveSkirtFaceMask=0x3f; uint64 Samples=0; double WorkerSeconds=0.0; std::chrono::steady_clock::time_point CpuQueuedAt{}; std::chrono::steady_clock::time_point CpuStartedAt{}; std::chrono::steady_clock::time_point CpuFinishedAt{}; bool bColdTimelineResidentReported=false; }; struct FStreamingGpuBatch { ID3D11Buffer* VertexBuffer=nullptr; ID3D11Buffer* IndexBuffer=nullptr; UINT IndexCount=0; UINT DrawOnlyIndexStart=0,DrawOnlyIndexCount=0; uint64 VertexCount=0; }; struct FCrossingWork { uint64 SubmittedJobs=0; uint64 PendingJobs=0; uint64 FinishedJobs=0; uint64 CancelledQueuedJobs=0; uint64 StaleResults=0; uint64 Tiles=0; uint64 Samples=0; double WorkerSeconds=0.0; double CorePageSeconds=0.0; double CorePageWorkerSeconds=0.0; uint64 PageCoveredTiles=0; uint64 PageRegions=0; uint64 PageLatticeNodes=0; FVoxelTileKey NearestNewTile{}; double NearestReadySeconds=-1.0; bool bHasNearestNewTile=false; uint64 TilesByLevel[MaxLevels+1]{}; uint64 SamplesByLevel[MaxLevels+1]{}; double WorkerSecondsByLevel[MaxLevels+1]{}; double WallSeconds=0.0; std::chrono::steady_clock::time_point StartTime{}; bool bReported=false; }; struct FGpuFarTile { ID3D11Buffer* VertexBuffer=nullptr; ID3D11Buffer* IndexBuffer=nullptr; ID3D11Buffer* IndirectArgs=nullptr; ID3D11Buffer* ConnectorVertexBuffer=nullptr; ID3D11Buffer* ConnectorIndexBuffer=nullptr; ID3D11Buffer* ReadbackCopyVertexBuffer=nullptr; ID3D11Buffer* ReadbackCopyIndexBuffer=nullptr; uint32 ReadbackCopyIndexCount=0; ID3D11Query* CompletionEvent=nullptr; VoxelForgeGpuFarViewer::GpuTimingQueries TimingQueries{}; uint64 VertexCapacityBytes=0; uint32 OutputSlot=0,IndirectArgsByteOffset=0,BatchIndex=UINT32_MAX; uint32 RequiredSurfaceVertexCount=0; int32 InputCells=0,InputStep=0; uint64 ProtectedSamples=0,ProtectedThinSamples=0,ProtectedSolidSamples=0; uint32 NearProxySamples=0,ConnectorRings=0,ConnectorVertices=0; uint8 VisibleSkirtFaceMask=0; bool bNearDetailInput=false; bool bSkirtDrawArgsAudited=false; double GpuDispatchMs=0.0; std::chrono::steady_clock::time_point PreparedAt{}; std::chrono::steady_clock::time_point SubmittedAt{}; std::chrono::steady_clock::time_point CompletedAt{}; bool bGpuComplete=false; bool bTimingResolved=false; bool bColdTimelineResidentReported=false; }; struct FGpuFarBatch { ID3D11Query* CompletionEvent=nullptr; VoxelForgeGpuFarViewer::GpuTimingQueries TimingQueries{}; uint32 TileCount=0; uint32 ResidentCount=0; std::vector 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; }; struct FGpuFarPanelOutputRange { uint32 BaseVertex=0; uint32 CapacityVertices=0; }; struct FGpuFarPanelFreeRange { uint32 BaseVertex=0; uint32 CapacityVertices=0; }; enum class EGpuWarmupLaunchPolicy { Auto, ForceDeferred, ForceEager }; uint64 HashStandaloneFile(const std::string& Path) { std::ifstream File(Path,std::ios::binary); if(!File)return 0; uint64 Hash=14695981039346656037ull; char Buffer[65536]; while(File) { File.read(Buffer,sizeof(Buffer)); const std::streamsize Count=File.gcount(); for(std::streamsize I=0;I(Buffer[I]); Hash*=1099511628211ull; } } return Hash; } FStandaloneBatchKey BatchForTile(const FVoxelTileKey& Tile) { return {Tile.Level,VoxelClipmapDesiredTiles::FloorDiv(Tile.Coord.X,8), VoxelClipmapDesiredTiles::FloorDiv(Tile.Coord.Y,8),Tile.Coord.Z}; } bool PrepareStandaloneDensityWorld(FStandaloneOwnerWorld& World,int32 Seed, bool bRoundTunnels,bool bEnhancedWalls,std::string& Error) { World.Generator.reset();World.Manager.reset(); World.Settings->Seed=Seed;World.Seed=Seed; // Keep the owner's walkable rooms, tunnels, and strate passages intact. The research // round field composes as additional air after the owner field, so it can widen/connect // spaces but cannot remove the authored entrance-to-exit route. World.Manager=std::make_unique(); if(!World.Manager->Initialize(World.Settings.get(),Seed)) {Error="standalone copied strate manager failed while applying viewer settings";return false;} World.Generator=std::make_unique(); World.Generator->InitializeSettings(World.Settings.get()); World.Generator->SetStrateManager(World.Manager.get()); World.Generator->bStandaloneResearchRoundTunnels=bRoundTunnels; World.Generator->bStandaloneResearchEnhancedWalls=bEnhancedWalls; return true; } struct FApp { struct FPreparedGpuFarInputResult { FVoxelTileKey Key; std::optional Input; std::string Error; std::chrono::steady_clock::time_point FinishedAt{}; uint64 FinishedFrame=0; }; struct FGpuFarPreparationBatch { std::once_flag StartOnce; std::chrono::steady_clock::time_point DispatchAt{}; std::chrono::steady_clock::time_point PrepareStart{}; std::chrono::steady_clock::time_point CpuReadyAt{}; std::atomic Remaining{0}; std::atomic Failed{0}; std::atomic WorkerNanoseconds{0}; std::atomic bCancelled{false}; uint64 Generation=0; std::size_t TileCount=0; std::size_t SharedWorkerCount=0; }; HWND Window=nullptr; ID3D11Device* Device=nullptr; ID3D11DeviceContext* Context=nullptr; IDXGISwapChain* SwapChain=nullptr; ID3D11RenderTargetView* RenderTarget=nullptr; ID3D11DepthStencilView* DepthView=nullptr; ID3D11VertexShader* VertexShader=nullptr; ID3D11PixelShader* PixelShader=nullptr; ID3D11InputLayout* InputLayout=nullptr; ID3D11Buffer* Constants=nullptr; ID3D11RasterizerState* SolidRasterizer=nullptr; ID3D11RasterizerState* WireRasterizer=nullptr; ID3D11DepthStencilState* DepthDisabledAuditState=nullptr; std::shared_ptr World; VoxelForgeCore::ResolvedWorldSnapshot Snapshot; std::unique_ptr ShapeWorld; std::unique_ptr PendingFullShapeWorld; FStandaloneCoreScheduler CoreScheduler; std::unique_ptr Streamer; std::thread FullShapeBuildThread; std::atomic bFullShapeBuildFinished{false}; bool bFullShapeBuildSucceeded=false; std::string FullShapeBuildError; std::chrono::steady_clock::time_point FullShapeBuildStart{}; FStandaloneMeshCache MeshCache; std::string DataPath; VFJson::Value OwnerJsonRoot; bool bHasCameraOverride=false; V3 CameraPositionOverride{}; float CameraYawOverride=0.0f,CameraPitchOverride=0.0f; std::unordered_map ResidentTiles; std::unordered_set DeferredLeaverTiles; std::unordered_set DesiredTileSet; std::unordered_map,FStandaloneBatchKeyHash> BatchMembers; std::unordered_map StreamingBatches; std::unordered_map GpuFarTiles; std::vector GpuFarBatches; std::deque GpuFarQueue; std::unordered_set GpuFarQueued; std::unordered_set GpuFarEligibleTiles; std::unordered_set DirtyBatchSet; std::unordered_map CrossingWork; std::vector DesiredTiles; std::vector InitialNeighborhoodTiles; int32 DesiredByLevel[MaxLevels+1]{}; uint64 GeneratedByLevel[MaxLevels+1]{}; uint64 SamplesByLevel[MaxLevels+1]{}; double WorkerSecondsByLevel[MaxLevels+1]{}; uint64 ProfileCyclesByLevel[MaxLevels+1][VoxelDensityProfile::BucketCount]{}; std::vector TileSecondsByLevel[MaxLevels+1]; uint64 CrossingIndex=0; bool bGenerationRunning=false; bool bRebuildPending=false; bool bParityChecked=false; bool bRoundTunnels=false; bool bRoundTunnelEnhanced=true; bool bShapeWorld=false; bool bWorldAssemblerPrototype=false; bool bWorldAssemblerAuditOnly=false; bool bShapePipelineActive=false; bool bNeighborhoodReadyReported=false; bool bShapeAuditOnly=false; bool bShapeCompare=false; bool bWalkabilityAuditOnly=false; bool bFarShapeStagePending=false; bool bGpuFarEnabled=false; bool bGpuFarPipelineInitialized=false; std::thread GpuPipelineStartupThread; bool bGpuPipelineStartupAttempted=false,bGpuPipelineStartupSucceeded=false; bool bGpuPipelineStartupWasDeferred=false; std::string GpuPipelineStartupError; bool bDisableGpuColdStartDrain=false; bool bGpuFarAuditEnabled=false; bool bGpuFarShaderPrewarm=false,bDisableGpuWarmupPresentHold=false; bool bGpuFarWarmupResourcesOnly=false; bool bGpuFarWarmupNormalPriority=false,bGpuFarWarmupBeforeWorkers=false; EGpuWarmupLaunchPolicy GpuWarmupLaunchPolicy=EGpuWarmupLaunchPolicy::Auto; bool bGpuWarmupDeferredUntilFirstView=false,bGpuWarmupDeferredStarted=false; bool bGpuWarmupCacheKeyAvailable=false; bool bGpuWarmupCacheWriteDisabled=false; std::filesystem::path GpuWarmupStatePath; std::string GpuWarmupCacheKey,GpuWarmupCacheIdentity; bool bGpuFarWarmupKernelFences=false; bool bGpuFarWarmupOnly=false; std::string GpuWarmupEntryFilter; std::thread GpuShaderWarmupThread; std::thread GpuWarmupPolicyThread; std::atomic bGpuWarmupPolicyResolutionFinished{false}; bool bGpuWarmupPolicyResolutionStarted=false; bool bGpuWarmupLaunchPolicyResolved=false; bool bGpuWarmupCacheMarkerMatches=false; double GpuWarmupPolicyResolutionMs=0.0; std::shared_ptr GpuFarPreparationState; std::mutex GpuFarPreparedResultsMutex; std::deque GpuFarPreparedResults; std::atomic GpuFarPreparationGeneration{0}; std::atomic bGpuFarPreparationFinished{false}; bool bGpuFarPreparationStarted=false,bGpuFarInputsFinalized=false; bool bGpuFarPreparationDeferredReported=false; bool bGpuFarFirstPreparedInputReported=false; bool bGpuWarmupCompleted=false,bGpuFarTimelineEnabled=false; bool bGpuFarNoPresent=false,bGpuFarNoPresentReported=false; bool bGpuWarmupRoutePending=false; bool bGpuShaderWarmupQueueSucceeded=false; std::atomic bGpuShaderWarmupQueueFinished{false}; bool bGpuWarmupContextProtected=false; std::string GpuShaderWarmupQueueError; std::chrono::steady_clock::time_point GpuShaderWarmupQueueStartedAt{},GpuShaderWarmupQueueFinishedAt{}; std::chrono::steady_clock::time_point CpuReadyFrameBeforeGpuAt{}; bool bGpuFarAuditReported=false; bool bGpuNearSkirtsEnabled=true,bGpuConnectorRepairEnabled=true; // The CPU fallback loses remote skirt coverage. bool bDisableVSync=false; bool bForceBlockingStartupPresent=false; bool bPresentCpuFrameBeforeGpu=false; bool bCpuReadyFramePresentedBeforeGpu=false; bool bQuitAfterClipmapClosePosted=false; bool bHoldCpuFrameDuringGpuWarmup=false,bGpuWarmupHoldReported=false; bool bGpuWarmupReleaseReported=false,bGpuWarmupPresentSkipReported=false; uint64 GpuWarmupHeldPresents=0; bool bAuditGpuSkirtDrawArgs=false,bGpuSkirtDrawAuditReported=false; bool bGpuFarDirectDrawAudit=false; bool bGpuFarReadbackCopyDrawAudit=false; bool bGpuFarMeterCopyDrawAudit=false; bool bGpuFarCpuMeshDrawAudit=false; bool bGpuFarDepthDisabledAudit=false,bGpuFarDepthDisabledAuditReported=false; bool bDrawOnlyCpuTriangleAuditReported=false; ID3D11Buffer* GpuSkirtArgsStaging=nullptr; uint64 GpuSkirtDrawAuditTiles=0,GpuSkirtDrawAuditZeroCounts=0, GpuSkirtDrawAuditOverflow=0,GpuSkirtDrawAuditBadStartIndex=0, GpuSkirtDrawAuditBadSurfaceArgs=0; uint64 GpuSkirtDrawAuditSumIndices=0,GpuSkirtDrawAuditMaxIndices=0; std::unique_ptr GpuFarAudit; bool bGpuFarFirstTileReported=false; std::filesystem::path GpuFarShaderPath; double GpuFarEnqueueWallSeconds=0.0; uint64 GpuFarTilesSubmitted=0; uint64 GpuFarNearTilesSubmitted=0,GpuFarFarTilesSubmitted=0; uint64 GpuFarPreparedNearTileInputs=0,GpuFarPreparedFarTileInputs=0; uint64 GpuFarNearLatticeSamples=0,GpuFarNearPackedCandidateSamples=0; uint64 GpuFarNearPackedSkippedSamples=0,GpuFarProtectedRouteSamples=0; uint64 GpuFarProtectedThinSamples=0,GpuFarProtectedSolidSamples=0; uint64 GpuFarProtectedSealSamples=0,GpuFarProtectedOverlaySamples=0; uint64 PresentCallCount=0; uint64 StartupNonBlockingPresentCalls=0,StartupNonBlockingPresentSkips=0; double GpuFarGpuDispatchMs=0.0; double GpuFarGpuDispatchMaxMs=0.0; FVoxelTileKey GpuFarGpuDispatchMaxKey{}; bool bGpuFarGpuDispatchMaxKeyValid=false; double GpuFarSubmissionSpanMs=0.0,GpuFarSubmissionSpanMaxMs=0.0; uint64 GpuFarLocalMemoryPeakBytes=0,GpuFarLocalMemoryBudgetBytes=0; double GpuFarPoolReserveMs=0.0; uint64 GpuFarSubmissionBatches=0; uint32 GpuFarMaxTilesPerSubmissionBatch=0; uint32 GpuFarOutputCapacitySlots=0,GpuFarNextOutputSlot=0; uint32 GpuFarOutputPoolReservedSlots=0; uint32 GpuFarPanelOutputHighWater=0,GpuFarPanelOutputReservedCapacityVertices=0; uint64 GpuFarOutputCountChecks=0,GpuFarOutputOverflowCount=0, GpuFarConnectorOverflowCount=0; uint64 GpuFarOutputCountReadbackFailures=0; uint32 GpuFarMaxRequiredVertices=0,GpuFarMaxRequiredOutputSlot=UINT32_MAX; FVoxelTileKey GpuFarMaxRequiredVertexKey{}; std::size_t GpuFarPreReservePoolSlots=0; int32 GpuFarPreReserveCoarseTileCells=0; std::vector GpuFarFreeOutputSlots; std::unordered_map GpuFarPreparedInputs; std::unordered_map GpuFarPreparationErrors; std::unordered_map GpuFarPreparedAt; std::vector GpuFarCandidateTiles,GpuFarBaseCpuFallbackTiles; std::vector GpuFarCpuFallbackTiles,GpuFarNeedPreparation; std::unordered_map GpuFarPanelOutputRanges; std::vector GpuFarPanelOutputFreeRanges; uint64 GpuFarWarmupCpuClaimedTiles=0,GpuFarWarmupGpuTakeoverTiles=0; double GpuFarPreparationWallMs=0.0,GpuFarPreparationWorkerMs=0.0; uint64 GpuFarPumpCalls=0,GpuFarCompletionPolls=0; double GpuFarFirstPumpMs=-1.0,GpuFarLastPumpMs=-1.0; double GpuFarFirstSubmitMs=-1.0,GpuFarLastSubmitMs=-1.0; double GpuFarFirstCompletionPollMs=-1.0,GpuFarLastCompletionPollMs=-1.0; double GpuFarPumpWallMs=0.0,GpuFarPumpMaxWallMs=0.0; double GpuFarPumpGapMs=0.0,GpuFarPumpGapMaxMs=0.0; std::chrono::steady_clock::time_point LastGpuFarPumpAt{}; std::chrono::steady_clock::time_point LastDrawEndAt{}; VoxelForgeCore::DetailVariant ShapeDetailVariant=VoxelForgeCore::DetailVariant::coherent; bool bWireframe=false; bool bCaptured=false; bool bAutoCaptureWritten=false; bool bFullDetailReported=false; bool bInitialClipmapReported=false; bool bWholeViewPresented=false; bool bGpuFirstBackedPresentReported=false; bool bProfileAttribution=false; bool bProfileDetailBand=false; bool bCompareEvaluators=false; bool bParityOnly=false; bool bDensityHash=false; int32 FlightTargetCrossings=0; int32 FlightObservedCrossings=0; uint64 FlightStartCrossingIndex=0; float FlightSpeedMps=16.0f; std::string FlightCaptureSequencePrefix; int32 FlightCaptureSequenceIndex=0; bool bFlightStarted=false; bool bFlightFinished=false; bool bFlightClosePosted=false; bool bFlightCrossingsValid=true; V3 FlightStartPosition{}; std::chrono::steady_clock::time_point FlightStartTime{}; bool bCaptureAfterClipmap=false; bool bQuitAfterClipmap=false; bool bPrintedClipOverride=false; bool bForceGenerate=false; std::string CapturePath; std::string MeshCachePath; std::chrono::steady_clock::time_point ColdProcessStart{}; std::atomic ColdTimelineFrameOrdinal{0}; std::chrono::steady_clock::time_point GenerationStart{}; bool bShowLevel[MaxLevels+1]={true,true,true,true,true,true,true,true,true}; bool Keys[256]{}; int32 Seed=0; int32 WorkerCount=8; int32 ClipRadius=3; int32 MaxClipLevelOverride=-1; int32 CaptureTileLimit=0; 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; V3 Position{}; POINT LastMouse{}; std::chrono::steady_clock::time_point PreviousFrame=std::chrono::steady_clock::now(); double FrameMs=0.0; uint64 TotalVertices=0; uint64 TotalIndices=0; FIntVector BuildTargetChunk=FIntVector::ZeroValue; int32 MaxBatchUploadsPerFrame=4; double BatchUploadBudgetMilliseconds=2.0; ~FApp(){ if(GpuWarmupPolicyThread.joinable())GpuWarmupPolicyThread.join(); if(GpuShaderWarmupThread.joinable())GpuShaderWarmupThread.join(); StopGeneration(true);ReleaseMeshes(); if(SolidRasterizer)SolidRasterizer->Release();if(WireRasterizer)WireRasterizer->Release(); if(DepthDisabledAuditState)DepthDisabledAuditState->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(); } static void ReleaseGpuFarTile(FGpuFarTile& Tile) { if(Tile.VertexBuffer)Tile.VertexBuffer->Release(); if(Tile.IndexBuffer)Tile.IndexBuffer->Release(); if(Tile.IndirectArgs)Tile.IndirectArgs->Release(); if(Tile.ConnectorVertexBuffer)Tile.ConnectorVertexBuffer->Release(); if(Tile.ConnectorIndexBuffer)Tile.ConnectorIndexBuffer->Release(); if(Tile.ReadbackCopyVertexBuffer)Tile.ReadbackCopyVertexBuffer->Release(); if(Tile.ReadbackCopyIndexBuffer)Tile.ReadbackCopyIndexBuffer->Release(); if(Tile.CompletionEvent)Tile.CompletionEvent->Release(); if(Tile.TimingQueries.start)Tile.TimingQueries.start->Release(); if(Tile.TimingQueries.end)Tile.TimingQueries.end->Release(); if(Tile.TimingQueries.disjoint)Tile.TimingQueries.disjoint->Release(); Tile={}; } double ColdTimelineMilliseconds(std::chrono::steady_clock::time_point At)const { return At.time_since_epoch().count()==0?-1.0: std::chrono::duration(At-ColdProcessStart).count(); } uint64 ColdTimelineFrame()const {return ColdTimelineFrameOrdinal.load(std::memory_order_relaxed);} static void ReleaseGpuFarBatch(FGpuFarBatch& Batch) { if(Batch.CompletionEvent)Batch.CompletionEvent->Release(); if(Batch.TimingQueries.start)Batch.TimingQueries.start->Release(); if(Batch.TimingQueries.end)Batch.TimingQueries.end->Release(); if(Batch.TimingQueries.disjoint)Batch.TimingQueries.disjoint->Release(); Batch={}; } void SampleGpuFarMemory() { if(!bGpuFarEnabled||!Device||!Context)return; uint64 Usage=0,Budget=0;std::string Error; if(VoxelForgeGpuFarViewer::QueryFarGpuMemory(Device,Context,GpuFarShaderPath, Usage,Budget,Error)) { GpuFarLocalMemoryPeakBytes=std::max(GpuFarLocalMemoryPeakBytes,Usage); GpuFarLocalMemoryBudgetBytes=Budget; } } void ReleaseMeshes() { for(auto& Pair:StreamingBatches) { if(Pair.second.VertexBuffer)Pair.second.VertexBuffer->Release(); if(Pair.second.IndexBuffer)Pair.second.IndexBuffer->Release(); } StreamingBatches.clear();BatchMembers.clear();ResidentTiles.clear(); for(auto& Pair:GpuFarTiles) ReleaseGpuFarTile(Pair.second); GpuFarTiles.clear(); for(FGpuFarBatch& Batch:GpuFarBatches)ReleaseGpuFarBatch(Batch); GpuFarBatches.clear();GpuFarQueue.clear();GpuFarQueued.clear();GpuFarEligibleTiles.clear(); GpuFarFreeOutputSlots.clear();GpuFarNextOutputSlot=0; GpuFarPreparedInputs.clear();GpuFarPreparationErrors.clear();GpuFarPreparedAt.clear(); GpuFarPreparationState.reset(); {std::lock_guard Lock(GpuFarPreparedResultsMutex);GpuFarPreparedResults.clear();} GpuFarCandidateTiles.clear();GpuFarBaseCpuFallbackTiles.clear(); GpuFarCpuFallbackTiles.clear();GpuFarNeedPreparation.clear(); GpuFarPanelOutputRanges.clear();GpuFarPanelOutputFreeRanges.clear(); GpuFarPanelOutputHighWater=GpuFarPanelOutputReservedCapacityVertices=0; bGpuFarPreparationStarted=false;bGpuFarInputsFinalized=false; bGpuFarPreparationDeferredReported=false; bGpuFarPreparationFinished.store(false,std::memory_order_relaxed); bGpuWarmupRoutePending=false; GpuFarWarmupCpuClaimedTiles=0;GpuFarWarmupGpuTakeoverTiles=0; GpuFarPreparationWallMs=0.0;GpuFarPreparationWorkerMs=0.0; bGpuFarFirstPreparedInputReported=false; GpuFarPumpCalls=0;GpuFarCompletionPolls=0; GpuFarFirstPumpMs=GpuFarLastPumpMs=GpuFarFirstSubmitMs=GpuFarLastSubmitMs=-1.0; GpuFarFirstCompletionPollMs=GpuFarLastCompletionPollMs=-1.0; GpuFarPumpWallMs=GpuFarPumpMaxWallMs=GpuFarPumpGapMs=GpuFarPumpGapMaxMs=0.0; LastGpuFarPumpAt={}; LastDrawEndAt={}; GpuFarAudit.reset();bGpuFarAuditReported=false; GpuFarTilesSubmitted=0;GpuFarEnqueueWallSeconds=0.0;GpuFarGpuDispatchMs=0.0; GpuFarNearTilesSubmitted=GpuFarFarTilesSubmitted=0; GpuFarPreparedNearTileInputs=GpuFarPreparedFarTileInputs=0; GpuFarNearLatticeSamples=GpuFarNearPackedCandidateSamples=0; GpuFarNearPackedSkippedSamples=GpuFarProtectedRouteSamples=0; GpuFarProtectedThinSamples=GpuFarProtectedSolidSamples=0; GpuFarProtectedSealSamples=GpuFarProtectedOverlaySamples=0; GpuFarOutputCountChecks=GpuFarOutputOverflowCount=GpuFarConnectorOverflowCount=0; GpuFarOutputCountReadbackFailures=0;GpuFarMaxRequiredVertices=0; GpuFarMaxRequiredOutputSlot=UINT32_MAX;GpuFarMaxRequiredVertexKey={}; GpuFarGpuDispatchMaxMs=0.0;GpuFarSubmissionSpanMs=0.0;GpuFarSubmissionSpanMaxMs=0.0; GpuFarGpuDispatchMaxKey={};bGpuFarGpuDispatchMaxKeyValid=false; GpuFarLocalMemoryPeakBytes=0;GpuFarLocalMemoryBudgetBytes=0; bGpuFarFirstTileReported=false; GpuSkirtDrawAuditTiles=GpuSkirtDrawAuditZeroCounts=GpuSkirtDrawAuditOverflow=0; GpuSkirtDrawAuditBadStartIndex=GpuSkirtDrawAuditBadSurfaceArgs=0; GpuSkirtDrawAuditSumIndices=GpuSkirtDrawAuditMaxIndices=0; GpuFarPoolReserveMs=0.0; GpuFarSubmissionBatches=0;GpuFarMaxTilesPerSubmissionBatch=0; GpuFarOutputPoolReservedSlots=0; GpuFarPanelOutputReservedCapacityVertices=0; DirtyBatchSet.clear();DesiredTiles.clear();DesiredTileSet.clear();CrossingWork.clear(); DeferredLeaverTiles.clear(); for(int32 I=0;I<=MaxLevels;++I) {DesiredByLevel[I]=0;GeneratedByLevel[I]=0;SamplesByLevel[I]=0;WorkerSecondsByLevel[I]=0.0; std::fill(std::begin(ProfileCyclesByLevel[I]),std::end(ProfileCyclesByLevel[I]),0); TileSecondsByLevel[I].clear();} TotalVertices=0;TotalIndices=0; } void StopGeneration(bool bCancel=false) { (void)bCancel; if(Streamer)Streamer->Stop(); Streamer.reset(); if(GpuPipelineStartupThread.joinable())GpuPipelineStartupThread.join(); GpuFarPreparationState.reset(); bGpuFarPreparationStarted=false; if(FullShapeBuildThread.joinable())FullShapeBuildThread.join(); PendingFullShapeWorld.reset(); bFullShapeBuildFinished.store(false,std::memory_order_relaxed); bFullShapeBuildSucceeded=false; FullShapeBuildError.clear(); InitialNeighborhoodTiles.clear(); bShapePipelineActive=false; bNeighborhoodReadyReported=false; bFarShapeStagePending=false; bGenerationRunning=false; } 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));} bool NeedsRecenter(const FIntVector& Center) const { return CameraChunk()!=Center; } bool MakeBuffer(ID3D11Buffer** Out,const void* Data,size_t Bytes,UINT Bind) { if(Bytes==0||Bytes>std::numeric_limits::max())return false; D3D11_BUFFER_DESC Desc{};Desc.ByteWidth=static_cast(Bytes); Desc.Usage=D3D11_USAGE_DEFAULT;Desc.BindFlags=Bind; D3D11_SUBRESOURCE_DATA Initial{};Initial.pSysMem=Data; return SUCCEEDED(Device->CreateBuffer(&Desc,&Initial,Out)); } static void AppendPngU32(std::vector& Out,uint32 Value) { Out.push_back(static_cast(Value >> 24)); Out.push_back(static_cast(Value >> 16)); Out.push_back(static_cast(Value >> 8)); Out.push_back(static_cast(Value)); } static uint32 PngCrc32(const uint8* Data,size_t Count) { uint32 Crc=0xffffffffu; for(size_t I=0;I>1)^((Crc&1)?0xedb88320u:0u); } return Crc^0xffffffffu; } static void AppendPngChunk(std::vector& Png,const char Type[4],const std::vector& Data) { AppendPngU32(Png,static_cast(Data.size())); const size_t CrcStart=Png.size(); Png.insert(Png.end(),Type,Type+4); Png.insert(Png.end(),Data.begin(),Data.end()); AppendPngU32(Png,PngCrc32(Png.data()+CrcStart,Png.size()-CrcStart)); } bool SaveBackBufferPng(const std::string& Path) { ID3D11Texture2D* BackBuffer=nullptr; if(FAILED(SwapChain->GetBuffer(0,IID_PPV_ARGS(&BackBuffer))))return false; D3D11_TEXTURE2D_DESC Desc{};BackBuffer->GetDesc(&Desc); Desc.Usage=D3D11_USAGE_STAGING;Desc.BindFlags=0;Desc.CPUAccessFlags=D3D11_CPU_ACCESS_READ;Desc.MiscFlags=0; ID3D11Texture2D* Staging=nullptr; const HRESULT CreateResult=Device->CreateTexture2D(&Desc,nullptr,&Staging); if(FAILED(CreateResult)){BackBuffer->Release();return false;} Context->CopyResource(Staging,BackBuffer);BackBuffer->Release(); D3D11_MAPPED_SUBRESOURCE Mapped{}; if(FAILED(Context->Map(Staging,0,D3D11_MAP_READ,0,&Mapped))){Staging->Release();return false;} const size_t RowBytes=static_cast(Desc.Width)*4; std::vector Raw((RowBytes+1)*Desc.Height); for(UINT Y=0;Y(Y)*(RowBytes+1); Row[0]=0; std::memcpy(Row+1,static_cast(Mapped.pData)+static_cast(Y)*Mapped.RowPitch,RowBytes); } Context->Unmap(Staging,0);Staging->Release(); std::vector Zlib{0x78,0x01}; uint32 AdlerA=1,AdlerB=0; for(const uint8 Byte:Raw){AdlerA=(AdlerA+Byte)%65521u;AdlerB=(AdlerB+AdlerA)%65521u;} for(size_t Offset=0;Offset(std::min(65535,Raw.size()-Offset)); const bool bFinal=Offset+Block==Raw.size(); Zlib.push_back(bFinal?1:0); Zlib.push_back(static_cast(Block));Zlib.push_back(static_cast(Block>>8)); const uint16 NotBlock=static_cast(~Block); Zlib.push_back(static_cast(NotBlock));Zlib.push_back(static_cast(NotBlock>>8)); Zlib.insert(Zlib.end(),Raw.begin()+Offset,Raw.begin()+Offset+Block); Offset+=Block; } AppendPngU32(Zlib,(AdlerB<<16)|AdlerA); std::vector Png{137,80,78,71,13,10,26,10}; std::vector Ihdr;AppendPngU32(Ihdr,Desc.Width);AppendPngU32(Ihdr,Desc.Height); Ihdr.insert(Ihdr.end(),{8,6,0,0,0});AppendPngChunk(Png,"IHDR",Ihdr); AppendPngChunk(Png,"IDAT",Zlib);AppendPngChunk(Png,"IEND",{}); std::ofstream File(Path,std::ios::binary); if(!File)return false; File.write(reinterpret_cast(Png.data()),static_cast(Png.size())); return File.good(); } bool Resize(UINT NewWidth,UINT NewHeight) { if(!Device||NewWidth==0||NewHeight==0)return false; Width=static_cast(NewWidth);Height=static_cast(NewHeight); if(RenderTarget){RenderTarget->Release();RenderTarget=nullptr;} if(DepthView){DepthView->Release();DepthView=nullptr;} if(SwapChain->ResizeBuffers(0,NewWidth,NewHeight,DXGI_FORMAT_UNKNOWN,0)!=S_OK)return false; ID3D11Texture2D* Back=nullptr; if(FAILED(SwapChain->GetBuffer(0,IID_PPV_ARGS(&Back))))return false; const HRESULT RtvResult=Device->CreateRenderTargetView(Back,nullptr,&RenderTarget);Back->Release(); if(FAILED(RtvResult))return false; D3D11_TEXTURE2D_DESC DepthDesc{};DepthDesc.Width=NewWidth;DepthDesc.Height=NewHeight; DepthDesc.MipLevels=1;DepthDesc.ArraySize=1;DepthDesc.Format=DXGI_FORMAT_D24_UNORM_S8_UINT; DepthDesc.SampleDesc.Count=1;DepthDesc.Usage=D3D11_USAGE_DEFAULT;DepthDesc.BindFlags=D3D11_BIND_DEPTH_STENCIL; ID3D11Texture2D* Depth=nullptr; if(FAILED(Device->CreateTexture2D(&DepthDesc,nullptr,&Depth)))return false; const HRESULT DsvResult=Device->CreateDepthStencilView(Depth,nullptr,&DepthView);Depth->Release(); return SUCCEEDED(DsvResult); } bool InitializeDevice() { DXGI_SWAP_CHAIN_DESC Desc{};Desc.BufferCount=1;Desc.BufferDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM; Desc.BufferUsage=DXGI_USAGE_RENDER_TARGET_OUTPUT;Desc.OutputWindow=Window;Desc.SampleDesc.Count=1; Desc.Windowed=TRUE;Desc.SwapEffect=DXGI_SWAP_EFFECT_DISCARD; D3D_FEATURE_LEVEL Feature{}; if(FAILED(D3D11CreateDeviceAndSwapChain(nullptr,D3D_DRIVER_TYPE_HARDWARE,nullptr,0,nullptr,0, D3D11_SDK_VERSION,&Desc,&SwapChain,&Device,&Feature,&Context)))return false; const char* ShaderSource=R"( cbuffer C:register(b0){float4x4 VP;float3 Camera;float FogStart;float3 Forward;float FogEnd;float3 LightDir;float Ambient;float4 Pad;} struct I{float3 p:POSITION;float3 n:NORMAL;}; struct O{float4 p:SV_POSITION;float3 world:TEXCOORD0;float3 n:NORMAL;}; O VS(I i){O o;float3 p=i.p*Pad.x;o.p=mul(float4(p,1),VP);o.world=p;o.n=normalize(i.n);return o;} float4 PS(O i):SV_TARGET{ float3 N=normalize(i.n);float3 V=normalize(Camera-i.world);float3 L=normalize(-LightDir); float Diffuse=saturate(dot(N,L));float Head=saturate(dot(N,V)); float Dist=length(Camera-i.world);float Atten=1.0-saturate(Dist/95.0); float3 Rock=lerp(float3(0.30,0.22,0.16),float3(0.48,0.43,0.34),saturate(N.z*0.5+0.5)); // Keep the camera fill broad and low-amplitude. The old squared, high-intensity // lobe made the 25 cm density-lattice normal variation read as horizontal bands. Head=Head*Atten; float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75; float Fog=saturate((Dist-FogStart)/(FogEnd-FogStart)); Lit=lerp(Lit,float3(0.10,0.14,0.19),Fog);return float4(Lit,1); })"; ID3DBlob* VsCode=nullptr;ID3DBlob* PsCode=nullptr;ID3DBlob* Errors=nullptr; HRESULT Hr=D3DCompile(ShaderSource,std::strlen(ShaderSource),nullptr,nullptr,nullptr,"VS","vs_5_0",0,0,&VsCode,&Errors); if(FAILED(Hr)){if(Errors)std::fprintf(stderr,"Vertex shader compile: %s\n",static_cast(Errors->GetBufferPointer()));if(Errors)Errors->Release();return false;} Hr=D3DCompile(ShaderSource,std::strlen(ShaderSource),nullptr,nullptr,nullptr,"PS","ps_5_0",0,0,&PsCode,&Errors); if(FAILED(Hr)){if(Errors)std::fprintf(stderr,"Pixel shader compile: %s\n",static_cast(Errors->GetBufferPointer()));if(Errors)Errors->Release();VsCode->Release();return false;} Hr=Device->CreateVertexShader(VsCode->GetBufferPointer(),VsCode->GetBufferSize(),nullptr,&VertexShader); if(SUCCEEDED(Hr))Hr=Device->CreatePixelShader(PsCode->GetBufferPointer(),PsCode->GetBufferSize(),nullptr,&PixelShader); D3D11_INPUT_ELEMENT_DESC Elements[]={{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0}, {"NORMAL",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0}}; if(SUCCEEDED(Hr))Hr=Device->CreateInputLayout(Elements,2,VsCode->GetBufferPointer(),VsCode->GetBufferSize(),&InputLayout); VsCode->Release();PsCode->Release();if(FAILED(Hr))return false; D3D11_BUFFER_DESC ConstantDesc{};ConstantDesc.ByteWidth=sizeof(FConstants);ConstantDesc.Usage=D3D11_USAGE_DEFAULT; ConstantDesc.BindFlags=D3D11_BIND_CONSTANT_BUFFER; if(FAILED(Device->CreateBuffer(&ConstantDesc,nullptr,&Constants)))return false; D3D11_RASTERIZER_DESC Raster{};Raster.FillMode=D3D11_FILL_SOLID;Raster.CullMode=D3D11_CULL_NONE; Raster.DepthClipEnable=TRUE;if(FAILED(Device->CreateRasterizerState(&Raster,&SolidRasterizer)))return false; Raster.FillMode=D3D11_FILL_WIREFRAME;if(FAILED(Device->CreateRasterizerState(&Raster,&WireRasterizer)))return false; D3D11_DEPTH_STENCIL_DESC NoDepth{};NoDepth.DepthEnable=FALSE; NoDepth.DepthWriteMask=D3D11_DEPTH_WRITE_MASK_ZERO;NoDepth.DepthFunc=D3D11_COMPARISON_ALWAYS; if(FAILED(Device->CreateDepthStencilState(&NoDepth,&DepthDisabledAuditState)))return false; if(!Resize(Width,Height))return false; return true; } bool EnsureGpuFarPipeline(std::string& Error) { if(!bGpuFarEnabled)return true; if(GpuPipelineStartupThread.joinable()) { GpuPipelineStartupThread.join(); if(!bGpuPipelineStartupSucceeded&&!bGpuPipelineStartupWasDeferred) { Error=GpuPipelineStartupError.empty() ?"overlapped GPU pipeline initialization failed":GpuPipelineStartupError; return false; } } if(bGpuFarPipelineInitialized)return true; if(!Device||!Context) {Error="D3D device is unavailable for the GPU far pipeline";return false;} const auto GpuPipelineStart=std::chrono::steady_clock::now(); std::printf("[ColdTimeline] stage=gpu_pipeline_init begin_ms=%.3f\n", std::chrono::duration(GpuPipelineStart-ColdProcessStart).count()); if(!VoxelForgeGpuFarViewer::InitializeFarPipeline(Device,Context,GpuFarShaderPath,Error)) { std::fprintf(stderr,"[GpuPipelineInitError] %s\n",Error.c_str()); return false; } bGpuFarPipelineInitialized=true; std::printf("[ColdTimeline] stage=gpu_pipeline_init end_ms=%.3f duration_ms=%.3f prewarm=%s\n", std::chrono::duration(std::chrono::steady_clock::now()-ColdProcessStart).count(), std::chrono::duration(std::chrono::steady_clock::now()-GpuPipelineStart).count(), bGpuFarShaderPrewarm?(bGpuFarWarmupResourcesOnly?"async_resources_only":"async_dispatch") :"disabled"); return true; } void StartGpuPipelineStartup(std::size_t PreReservePoolSlots,int32 CoarseTileCells) { if(!bGpuFarEnabled||bGpuFarPipelineInitialized||GpuPipelineStartupThread.joinable() ||bGpuPipelineStartupAttempted||bGpuFarWarmupBeforeWorkers)return; if(!Device||!Context)return; bGpuPipelineStartupAttempted=true; GpuPipelineStartupThread=std::thread([this,PreReservePoolSlots,CoarseTileCells]() { ResolveGpuWarmupLaunchPolicy(true); if(bGpuWarmupDeferredUntilFirstView) { bGpuPipelineStartupWasDeferred=true; std::printf("[GpuPipelineOverlap] status=deferred reason=launch_policy_after_first_CPU_view\n"); return; } if(!SetGpuWarmupContextProtection(true)) { bGpuPipelineStartupWasDeferred=true; std::printf("[GpuPipelineOverlap] status=deferred reason=immediate_context_protection_unavailable\n"); return; } const auto PipelineStart=std::chrono::steady_clock::now(); std::printf("[GpuPipelineStartup] status=started action=pipeline_init_and_output_pool phase=post_shape_compile_before_cpu_workers\n"); std::printf("[ColdTimeline] stage=gpu_pipeline_init begin_ms=%.3f phase=post_shape_compile_before_cpu_workers\n", std::chrono::duration(PipelineStart-ColdProcessStart).count()); if(!VoxelForgeGpuFarViewer::InitializeFarPipeline(Device,Context,GpuFarShaderPath, GpuPipelineStartupError)) { bGpuPipelineStartupSucceeded=false; SetGpuWarmupContextProtection(false); std::fprintf(stderr,"[GpuPipelineInitError] overlapped: %s\n", GpuPipelineStartupError.c_str()); return; } bGpuFarPipelineInitialized=true; bGpuPipelineStartupSucceeded=true; std::printf("[ColdTimeline] stage=gpu_pipeline_init end_ms=%.3f duration_ms=%.3f prewarm=%s phase=post_shape_compile_before_cpu_workers\n", std::chrono::duration(std::chrono::steady_clock::now()-ColdProcessStart).count(), std::chrono::duration(std::chrono::steady_clock::now()-PipelineStart).count(), bGpuFarShaderPrewarm?(bGpuFarWarmupResourcesOnly?"async_resources_only":"async_dispatch") :"disabled"); if(PreReservePoolSlots>0) { const auto PoolStart=std::chrono::steady_clock::now(); std::printf("[ColdTimeline] stage=gpu_output_pool_precompile begin_ms=%.3f slots=%zu phase=post_shape_compile_before_cpu_workers\n", ColdTimelineMilliseconds(PoolStart),PreReservePoolSlots); std::string PoolError; if(VoxelForgeGpuFarViewer::ReserveFarOutputPool(Device,Context,GpuFarShaderPath, static_cast(PreReservePoolSlots),static_cast(CoarseTileCells),PoolError,0)) { GpuFarOutputCapacitySlots=static_cast(PreReservePoolSlots); GpuFarOutputPoolReservedSlots=GpuFarOutputCapacitySlots; GpuFarPanelOutputReservedCapacityVertices=0; const double PoolMs=std::chrono::duration( std::chrono::steady_clock::now()-PoolStart).count(); GpuFarPoolReserveMs+=PoolMs; std::printf("[ColdTimeline] stage=gpu_output_pool_precompile end_ms=%.3f duration_ms=%.3f reserved_slots=%u phase=post_shape_compile_before_cpu_workers\n", ColdTimelineMilliseconds(std::chrono::steady_clock::now()),PoolMs, GpuFarOutputPoolReservedSlots); } else std::fprintf(stderr,"[GpuFarPoolError] precompile reservation deferred: %s\n", PoolError.c_str()); } // Shader warmup issues a long queue of GPU work and can throttle the // CPU-heavy detail pass and initial meshing. Pipeline and pool setup // start after shape compilation, before the CPU stream workers. if(!bGpuFarShaderPrewarm||bGpuWarmupCompleted) SetGpuWarmupContextProtection(false); }); } bool BuildGpuWarmupCacheKey() { GpuWarmupCacheKey.clear(); GpuWarmupCacheIdentity.clear(); if(!Device||GpuFarShaderPath.empty())return false; IDXGIDevice* DxgiDevice=nullptr; if(FAILED(Device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast(&DxgiDevice)))||!DxgiDevice)return false; IDXGIAdapter* Adapter=nullptr; const HRESULT AdapterResult=DxgiDevice->GetAdapter(&Adapter); DxgiDevice->Release(); if(FAILED(AdapterResult)||!Adapter)return false; DXGI_ADAPTER_DESC AdapterDesc{}; const HRESULT DescResult=Adapter->GetDesc(&AdapterDesc); LARGE_INTEGER DriverVersion{}; const HRESULT DriverResult=Adapter->CheckInterfaceSupport( __uuidof(IDXGIDevice),&DriverVersion); Adapter->Release(); if(FAILED(DescResult)||FAILED(DriverResult))return false; static constexpr std::array WarmupEntries={ "EvaluateFarFieldCS","EvaluateNearFieldCS","ClassifyCS","ClassifyFarCS", "ScanGroupsCS","EmitCS","ApplyNearFieldDetailCS","EmitNearCS", "BuildFarConnectorRingsCS","EmitFarConnectorPanelsCS","ClassifyFarSkirtsCS", "ScanFarSkirtsCS","EmitFarSkirtsCS","NoiseProbeCS"}; uint64 ShaderSetHash=14695981039346656037ull; const auto MixText=[&](std::string_view Text) { for(const unsigned char Byte:Text) {ShaderSetHash^=Byte;ShaderSetHash*=1099511628211ull;} ShaderSetHash^=0xffu;ShaderSetHash*=1099511628211ull; }; const auto MixFile=[&](const std::filesystem::path& Path,bool bRequired) { std::error_code Ec; const bool bExists=std::filesystem::is_regular_file(Path,Ec)&&!Ec; MixText(Path.filename().string()); if(!bExists) { MixText("missing"); return !bRequired; } const uint64 FileHash=HashStandaloneFile(Path.string()); if(FileHash==0)return false; const uint64 FileSize=std::filesystem::file_size(Path,Ec); if(Ec)return false; MixText(std::to_string(FileSize)); MixText(std::to_string(FileHash)); return true; }; MixText("gpu-far-warmup-signature-v2"); const std::filesystem::path ShaderImplementation=GpuFarShaderPath.parent_path() .parent_path()/"gpu_field_port"/"GpuFieldPort.cpp"; const std::filesystem::path ViewerImplementation=GpuFarShaderPath.parent_path() .parent_path()/"gpu_field_port"/"GpuFarViewer.h"; if(!MixFile(GpuFarShaderPath,true)||!MixFile(ShaderImplementation,true) ||!MixFile(ViewerImplementation,true))return false; const std::filesystem::path PrecompiledDirectory= VoxelForgeGpuFarViewer::ExecutablePrecompiledShaderDirectory(GpuFarShaderPath); for(const char* Entry:WarmupEntries) if(!MixFile(PrecompiledDirectory/(std::string(Entry)+".cso"),true))return false; // Step 29 changes only shader lookup and CPU/GPU routing. When every // warmup bytecode file is identical to Step 28's pinned bundle, retain // its marker identity so an already-warmed driver can skip redundant // startup dispatches. A changed or incomplete bytecode set keeps the // normal content-derived identity and warmup path. if(PrecompiledDirectory.filename()=="VoxelForgeGpuFarStep29") { bool bStep28BytecodeIdentical=true; const std::filesystem::path Step28Directory=PrecompiledDirectory.parent_path(); for(const char* Entry:WarmupEntries) { const std::filesystem::path Current=PrecompiledDirectory/(std::string(Entry)+".cso"); const std::filesystem::path Step28=Step28Directory/(std::string(Entry)+".cso"); std::error_code CurrentEc,Step28Ec; const uint64 CurrentSize=std::filesystem::file_size(Current,CurrentEc); const uint64 Step28Size=std::filesystem::file_size(Step28,Step28Ec); if(CurrentEc||Step28Ec||CurrentSize!=Step28Size ||HashStandaloneFile(Current.string())!=HashStandaloneFile(Step28.string())) {bStep28BytecodeIdentical=false;break;} } if(bStep28BytecodeIdentical) { ShaderSetHash=0x6B94E565889F96F2ull; std::printf("[GpuWarmupBytecodeAlias] applied=step28_identical_shader_set entries=%zu\n", WarmupEntries.size()); } } std::ostringstream Identity; Identity<<"adapter_luid="<(AdapterDesc.AdapterLuid.HighPart)<<":"<(DriverVersion.QuadPart) <<" shader_set=0x"<( std::chrono::steady_clock::now()-ResolveStart).count(); bGpuWarmupPolicyResolutionFinished.store(true,std::memory_order_release); }); std::printf("[ColdTimeline] event=gpu_warmup_policy_async_started at_ms=%.3f default_route=%s\n", std::chrono::duration( std::chrono::steady_clock::now()-ColdProcessStart).count(), bGpuWarmupDeferredUntilFirstView?"after_first_CPU_view":"startup_overlap"); } bool ResolveGpuWarmupLaunchPolicy(bool bWaitForResolution=false) { if(!bGpuFarEnabled||!bGpuFarShaderPrewarm)return true; if(!bGpuWarmupPolicyResolutionStarted)StartGpuWarmupPolicyResolutionAsync(); if(bGpuWarmupLaunchPolicyResolved)return true; if(!bGpuWarmupPolicyResolutionFinished.load(std::memory_order_acquire)) { if(!bWaitForResolution)return false; if(GpuWarmupPolicyThread.joinable())GpuWarmupPolicyThread.join(); } else if(GpuWarmupPolicyThread.joinable())GpuWarmupPolicyThread.join(); if(!bGpuWarmupPolicyResolutionFinished.load(std::memory_order_acquire))return false; if(bGpuFarWarmupBeforeWorkers) { bGpuWarmupDeferredUntilFirstView=false; std::printf("[GpuWarmupLaunchDecision] mode=before_workers cache_marker=%s key_available=%s identity=%s resolution_ms=%.3f\n", bGpuWarmupCacheMarkerMatches?"match":"miss", bGpuWarmupCacheKeyAvailable?"yes":"no", bGpuWarmupCacheKeyAvailable?GpuWarmupCacheIdentity.c_str():"unavailable", GpuWarmupPolicyResolutionMs); bGpuWarmupLaunchPolicyResolved=true; return true; } const bool bDeferredRouteWasAlreadyStarted=bGpuWarmupDeferredStarted; if(GpuWarmupLaunchPolicy==EGpuWarmupLaunchPolicy::ForceDeferred) bGpuWarmupDeferredUntilFirstView=true; else if(GpuWarmupLaunchPolicy==EGpuWarmupLaunchPolicy::ForceEager) bGpuWarmupDeferredUntilFirstView=false; else bGpuWarmupDeferredUntilFirstView=!bGpuWarmupCacheMarkerMatches ||bDeferredRouteWasAlreadyStarted; const char* Mode=GpuWarmupLaunchPolicy==EGpuWarmupLaunchPolicy::ForceDeferred ?"forced_cold_start":(GpuWarmupLaunchPolicy==EGpuWarmupLaunchPolicy::ForceEager ?"forced_cached_start":"auto"); std::printf("[GpuWarmupLaunchDecision] mode=%s cache_marker=%s route=%s key_available=%s state_path=%s identity=%s resolution_ms=%.3f\n", Mode,bGpuWarmupCacheMarkerMatches?"match":"miss", bGpuWarmupDeferredUntilFirstView?"after_first_CPU_view":"startup_overlap", bGpuWarmupCacheKeyAvailable?"yes":"no",GpuWarmupStatePath.string().c_str(), bGpuWarmupCacheKeyAvailable?GpuWarmupCacheIdentity.c_str():"unavailable", GpuWarmupPolicyResolutionMs); bGpuWarmupLaunchPolicyResolved=true; if(!bGpuWarmupDeferredUntilFirstView&&bGpuWarmupCacheMarkerMatches) { // This exact adapter/driver/shader key was recorded only after a // successful warmup. Replaying tiny dispatches every process start // competes with shape and tile workers without changing the pipeline. bGpuWarmupCompleted=true; std::printf("[GpuWarmupCacheHit] action=skip_redundant_dispatches identity=%s\n", GpuWarmupCacheIdentity.c_str()); } return true; } void MarkGpuWarmupCacheReady() { if(bGpuWarmupCacheWriteDisabled) { std::printf("[GpuWarmupCacheState] result=write_disabled policy=command_line\n"); return; } if(!bGpuFarShaderPrewarm||bGpuFarWarmupResourcesOnly ||!GpuWarmupEntryFilter.empty()||GpuWarmupStatePath.empty())return; ResolveGpuWarmupLaunchPolicy(true); if(!bGpuWarmupCacheKeyAvailable)return; const std::filesystem::path TemporaryPath=GpuWarmupStatePath.wstring() +L"."+std::to_wstring(GetCurrentProcessId())+L".tmp"; { std::ofstream Marker(TemporaryPath,std::ios::binary|std::ios::trunc); if(!Marker) { std::fprintf(stderr,"[GpuWarmupCacheState] write_failed path=%s reason=open_failed\n", TemporaryPath.string().c_str()); return; } Marker<(Error)); return; } std::printf("[GpuWarmupCacheState] result=recorded path=%s identity=%s\n", GpuWarmupStatePath.string().c_str(),GpuWarmupCacheIdentity.c_str()); } bool SetGpuWarmupContextProtection(bool bProtected) { if(!Context)return false; if(bGpuWarmupContextProtected==bProtected)return true; ID3D11Multithread* Multithread=nullptr; if(FAILED(Context->QueryInterface(__uuidof(ID3D11Multithread), reinterpret_cast(&Multithread)))||!Multithread)return false; Multithread->SetMultithreadProtected(bProtected?TRUE:FALSE); Multithread->Release(); bGpuWarmupContextProtected=bProtected; return true; } void StartGpuShaderWarmupAsync(bool bShapeCompileOverlap=false) { if(!bGpuFarShaderPrewarm||bGpuWarmupCompleted||GpuShaderWarmupThread.joinable())return; bGpuShaderWarmupQueueSucceeded=false;GpuShaderWarmupQueueError.clear(); bGpuShaderWarmupQueueFinished.store(false,std::memory_order_relaxed); GpuShaderWarmupQueueStartedAt=std::chrono::steady_clock::now(); GpuShaderWarmupQueueFinishedAt={}; const bool bContextProtected=SetGpuWarmupContextProtection(true); if(!bContextProtected) std::fprintf(stderr,"[GpuWarmupContextProtection] enable_failed; async immediate-context protection is unavailable\n"); GpuShaderWarmupThread=std::thread([this]() { const bool bPreserveAuditPriority=bGpuFarWarmupBeforeWorkers||bGpuFarAuditEnabled; const int WarmupPriority=bGpuFarWarmupNormalPriority?THREAD_PRIORITY_HIGHEST: (bPreserveAuditPriority?THREAD_PRIORITY_BELOW_NORMAL:THREAD_PRIORITY_NORMAL); const bool bPrioritySet=SetThreadPriority(GetCurrentThread(),WarmupPriority)!=0; const char* RelativePriority=bGpuFarWarmupNormalPriority?"Highest": (bPreserveAuditPriority?"BelowNormal":"Normal"); std::printf("[GpuShaderWarmupThread] priority=%s process=BelowNormal thread_relative=%s purpose=%s\n", bPrioritySet?RelativePriority:"set_failed",RelativePriority, bGpuWarmupDeferredUntilFirstView?"post_first_CPU_view": (bPreserveAuditPriority?"audit_or_before_workers":"cache_candidate_startup")); std::fflush(stdout); bGpuShaderWarmupQueueSucceeded=VoxelForgeGpuFarViewer::QueueFarShaderWarmup( Device,Context,GpuFarShaderPath,!bGpuFarWarmupResourcesOnly,GpuWarmupEntryFilter, bGpuFarWarmupKernelFences, GpuShaderWarmupQueueError); GpuShaderWarmupQueueFinishedAt=std::chrono::steady_clock::now(); if(bGpuFarTimelineEnabled) std::printf("[ColdTimeline] event=gpu_warmup_queue_finished at_ms=%.3f queue_ms=%.3f success=%s\n", ColdTimelineMilliseconds(GpuShaderWarmupQueueFinishedAt), std::chrono::duration( GpuShaderWarmupQueueFinishedAt-GpuShaderWarmupQueueStartedAt).count(), bGpuShaderWarmupQueueSucceeded?"yes":"no"); bGpuShaderWarmupQueueFinished.store(true,std::memory_order_release); }); std::printf("[GpuShaderWarmup] queue_thread=started overlap=%s\n", bGpuWarmupDeferredUntilFirstView?"after_first_CPU_view": (bGpuFarWarmupBeforeWorkers?"none_before_generation_workers": (bShapeCompileOverlap?"shape_compile":"CPU_world_configuration"))); std::fflush(stdout); } size_t PrintParity() { if(bParityChecked||!World)return 0; const auto ParityStart=std::chrono::steady_clock::now(); bParityChecked=true;size_t MismatchCount=0; std::map Kinds; for(size_t I=0;IDensitySamples.size();++I) { const FStandaloneParitySample& S=World->DensitySamples[I]; const float Actual=World->Generator->GetDensityAt(static_cast(S.PositionVoxels.X), static_cast(S.PositionVoxels.Y),static_cast(S.PositionVoxels.Z)); ++Kinds[S.Kind]; if(std::bit_cast(Actual)!=std::bit_cast(S.PluginDensity)) { ++MismatchCount; std::fprintf(stderr,"PARITY MISMATCH %s strate=%d voxels=(%.6f,%.6f,%.6f) plugin=%.9g standalone=%.9g\n", S.Kind.c_str(),S.StrateIndex,S.PositionVoxels.X,S.PositionVoxels.Y,S.PositionVoxels.Z,S.PluginDensity,Actual); } } std::printf("Density parity: %zu/%zu bit-identical; mismatches=%zu\n", World->DensitySamples.size()-MismatchCount,World->DensitySamples.size(),MismatchCount); for(const auto& [Kind,Count]:Kinds)std::printf(" %-24s %zu\n",Kind.c_str(),Count); std::printf("[DiagnosticProfile] stage=density_parity samples=%zu duration_ms=%.3f\n", World->DensitySamples.size(),std::chrono::duration( std::chrono::steady_clock::now()-ParityStart).count()); std::fflush(stdout); return MismatchCount; } bool ConfigureWorld(std::string& Error) { const auto ConfigureStart=std::chrono::steady_clock::now(); ShapeWorld.reset(); Snapshot={}; World=std::make_shared(); const auto ResolveStart=std::chrono::steady_clock::now(); if(!StandaloneOwnerLoader::Resolve(OwnerJsonRoot,*World,Error))return false; const auto ResolveEnd=std::chrono::steady_clock::now(); std::printf("[ConfigureProfile] stage=owner_resolve duration_ms=%.3f\n", std::chrono::duration(ResolveEnd-ResolveStart).count()); if(!bParityChecked&&Seed==World->Seed&&!bRoundTunnels) std::printf("[DiagnosticDeferred] density_parity=--parity-only samples=%zu\n", World->DensitySamples.size()); const auto ClipOverrideStart=std::chrono::steady_clock::now(); const int32 ExportClipRadius=World->ClipRadius; World->ClipRadius=ClipRadius; World->Settings->ClipRadius=ClipRadius; if(!bPrintedClipOverride) { bPrintedClipOverride=true; const double FullDetailWidth=static_cast(2*ClipRadius+2) *CHUNK_SIZE*VOXEL_SIZE/100.0; std::printf("Standalone clip override: exported radius=%d (112 m cube) -> radius=%d (%.0f m LOD0 cube), voxel size=25 cm.\n", ExportClipRadius,ClipRadius,FullDetailWidth); } std::printf("[ConfigureProfile] stage=clip_override duration_ms=%.3f\n", std::chrono::duration(std::chrono::steady_clock::now()-ClipOverrideStart).count()); const auto DensitySetupStart=std::chrono::steady_clock::now(); if(!PrepareStandaloneDensityWorld(*World,Seed,bRoundTunnels, bRoundTunnelEnhanced,Error))return false; std::printf("[ConfigureProfile] stage=density_world_setup duration_ms=%.3f\n", std::chrono::duration(std::chrono::steady_clock::now()-DensitySetupStart).count()); if(MaxClipLevelOverride>=0) { World->MaxClipLevel=MaxClipLevelOverride; World->Settings->MaxClipLevel=MaxClipLevelOverride; std::printf("Standalone max clip level override applied after world reload: max_level=%d.\n", MaxClipLevelOverride); } const auto ShapeSetupStart=std::chrono::steady_clock::now(); if(bShapeWorld&&!BuildShapeWorldForCamera(Error,true,false,true))return false; std::printf("[ConfigureProfile] stage=shape_world_request duration_ms=%.3f\n", std::chrono::duration(std::chrono::steady_clock::now()-ShapeSetupStart).count()); const auto CacheStart=std::chrono::steady_clock::now(); LoadMeshCache(); std::printf("[ConfigureProfile] stage=mesh_cache duration_ms=%.3f\n", std::chrono::duration(std::chrono::steady_clock::now()-CacheStart).count()); std::printf("[ConfigureProfile] stage=configure_total duration_ms=%.3f\n", std::chrono::duration(std::chrono::steady_clock::now()-ConfigureStart).count()); return true; } void PopulateGpuVisualDetailBandPlan(VoxelForgeCore::ShapeBuildRequest& Request, const std::vector& TileKeys) const { if(!bGpuFarEnabled||!bProfileDetailBand)return; std::unordered_set TileSet; TileSet.reserve(TileKeys.size()*2+1); for(const FVoxelTileKey& Key:TileKeys)TileSet.insert(Key); for(const FVoxelTileKey& Key:TileKeys) { if(Key.Level<0||Key.Level>=World->FullResClipLevels)continue; const FIntVector Origin=Key.OriginVoxels(); VoxelForgeCore::DetailBandTileRegion Region; Region.originVoxel={Origin.X,Origin.Y,Origin.Z}; Region.cells=CHUNK_SIZE; Region.step=std::max(1,Key.ExtentVoxels()/CHUNK_SIZE); const uint8 VisibleSkirts=World->bGenerateSkirts ?ComputeVisibleSkirtFaceMask(Key,TileSet):0; if(VisibleSkirts==0||bGpuNearSkirtsEnabled) Request.gpuVisualDetailTiles.push_back(Region); else Request.cpuVisualDetailTiles.push_back(Region); } } bool BuildShapeWorldForCamera(std::string& Error,bool bIncludeFarWorld=false, bool bNeighborhoodOnly=false, bool bDeferWalkabilityValidation=false) { const auto RequestSetupStart=std::chrono::steady_clock::now(); const FVector CameraVoxels(Position.X*4.0,Position.Y*4.0,Position.Z*4.0); const FStandaloneDesiredTileSet Desired=StandaloneWorldMesher::BuildDesiredSet(*World,CameraVoxels); FIntVector Min(INT32_MAX,INT32_MAX,INT32_MAX),Max(INT32_MIN,INT32_MIN,INT32_MIN); FIntVector ClipMin(INT32_MAX,INT32_MAX,INT32_MAX),ClipMax(INT32_MIN,INT32_MIN,INT32_MIN); uint64 FineTiles=0; InitialNeighborhoodTiles.clear(); const FIntVector CenterChunk=Desired.CenterChunk; for(const FVoxelTileKey& Tile:Desired.Tiles) { const FIntVector Origin=Tile.OriginVoxels(); const int32 Extent=Tile.ExtentVoxels(); ClipMin.X=std::min(ClipMin.X,Origin.X);ClipMin.Y=std::min(ClipMin.Y,Origin.Y);ClipMin.Z=std::min(ClipMin.Z,Origin.Z); ClipMax.X=std::max(ClipMax.X,Origin.X+Extent);ClipMax.Y=std::max(ClipMax.Y,Origin.Y+Extent);ClipMax.Z=std::max(ClipMax.Z,Origin.Z+Extent); if(bNeighborhoodOnly) { if(Tile.Level!=0||std::abs(Tile.Coord.X-CenterChunk.X)>1 ||std::abs(Tile.Coord.Y-CenterChunk.Y)>1 ||std::abs(Tile.Coord.Z-CenterChunk.Z)>1)continue; InitialNeighborhoodTiles.push_back(Tile); } else if(Tile.Level>=World->FullResClipLevels)continue; Min.X=std::min(Min.X,Origin.X);Min.Y=std::min(Min.Y,Origin.Y);Min.Z=std::min(Min.Z,Origin.Z); Max.X=std::max(Max.X,Origin.X+Extent);Max.Y=std::max(Max.Y,Origin.Y+Extent);Max.Z=std::max(Max.Z,Origin.Z+Extent); ++FineTiles; } if(!FineTiles){Error="no full-detail tiles are available for shape compilation";return false;} if(bNeighborhoodOnly) { if(InitialNeighborhoodTiles.size()!=27) {Error="the 3x3x3 player neighborhood does not contain 27 LOD0 tiles";return false;} constexpr int32 NearBuildPad=64; Min.X-=NearBuildPad;Min.Y-=NearBuildPad;Min.Z-=NearBuildPad; Max.X+=NearBuildPad;Max.Y+=NearBuildPad;Max.Z+=NearBuildPad; } const auto DesiredSetupEnd=std::chrono::steady_clock::now(); std::printf("[ConfigureProfile] stage=desired_tiles_and_bounds tiles=%llu duration_ms=%.3f\n", static_cast(FineTiles),std::chrono::duration( DesiredSetupEnd-RequestSetupStart).count()); const auto SnapshotStart=std::chrono::steady_clock::now(); Snapshot=VoxelForgeCore::MakeStandaloneSnapshotFromParsedJson(OwnerJsonRoot,Seed,ClipRadius, MaxClipLevelOverride,bRoundTunnels,bRoundTunnelEnhanced,Error); if(!Snapshot) {if(Error.empty())Error="the standalone adapter could not make a resolved core snapshot";return false;} ShapeWorld=std::make_unique(Snapshot); const int32 ShapeWorkers=bNeighborhoodOnly?(WorkerCount>=8?2:1):WorkerCount; VoxelForgeCore::ShapeBuildRequest Request; Request.minVoxel={Min.X,Min.Y,Min.Z};Request.maxVoxel={Max.X,Max.Y,Max.Z}; Request.clipMinVoxel={ClipMin.X,ClipMin.Y,ClipMin.Z}; Request.clipMaxVoxel={ClipMax.X,ClipMax.Y,ClipMax.Z}; Request.workerLimit=static_cast(ShapeWorkers);Request.detail=ShapeDetailVariant; Request.includeFarWorld=bIncludeFarWorld;Request.roundTunnels=bRoundTunnels; Request.enhancedTunnelWalls=bRoundTunnelEnhanced; Request.profileDetailBand=bProfileDetailBand; PopulateGpuVisualDetailBandPlan(Request, bNeighborhoodOnly?InitialNeighborhoodTiles:Desired.Tiles); Request.validatePassageRoutes=!bDeferWalkabilityValidation; if(bDeferWalkabilityValidation) std::printf("[DiagnosticDeferred] walkability=full_headless_or_route_audit workers=8 samples=5642\n"); GpuFarPreReservePoolSlots=0; GpuFarPreReserveCoarseTileCells=World->CoarseTileCells; const bool bCanPreReservePool=bGpuFarEnabled&&bIncludeFarWorld&&!bNeighborhoodOnly &&!bCaptureOnlyTile&&!(CaptureTileLimit>0&&!CapturePath.empty()); if(bCanPreReservePool) { std::unordered_set PoolDesiredSet; PoolDesiredSet.reserve(Desired.Tiles.size()*2+1); for(const FVoxelTileKey& Key:Desired.Tiles)PoolDesiredSet.insert(Key); const int32 ShapeMin[3]={Min.X-2,Min.Y-2,Min.Z-2}; const int32 ShapeMax[3]={Max.X+2,Max.Y+2,Max.Z+2}; for(const FVoxelTileKey& Key:Desired.Tiles) { if(Key.Level<0)continue; if(Key.LevelFullResClipLevels) { if(!World->bGenerateSkirts||bGpuNearSkirtsEnabled ||ComputeVisibleSkirtFaceMask(Key,PoolDesiredSet)==0) ++GpuFarPreReservePoolSlots; continue; } if(Key.Level>8)continue; const int32 Cells=std::max(1,World->CoarseTileCells); if(Cells>32)continue; const int32 Extent=CHUNK_SIZE<(ShapeMin[Axis])-Origins[Axis])/Step); const double Last=std::floor((static_cast(ShapeMax[Axis])-Origins[Axis])/Step); if(First>Cells+1||Last< -1){bOutsideNearRegion=true;break;} } if(bOutsideNearRegion)++GpuFarPreReservePoolSlots; } std::printf("[GpuOutputPoolPreReservePlan] desired=%zu candidate_slots=%zu status=geometry_match\n", Desired.Tiles.size(),GpuFarPreReservePoolSlots); } const auto ShapeCompileStart=std::chrono::steady_clock::now(); std::printf("[ConfigureProfile] stage=snapshot_and_build_request duration_ms=%.3f\n", std::chrono::duration(ShapeCompileStart-SnapshotStart).count()); std::printf("[ColdTimeline] stage=shape_compile begin_ms=%.3f\n", std::chrono::duration(ShapeCompileStart-ColdProcessStart).count()); if(!ShapeWorld->compile(Request,CoreScheduler,Error)) {ShapeWorld.reset();return false;} const auto ShapeCompileEnd=std::chrono::steady_clock::now(); std::printf("[ColdTimeline] stage=shape_compile end_ms=%.3f duration_ms=%.3f\n", std::chrono::duration(ShapeCompileEnd-ColdProcessStart).count(), std::chrono::duration(ShapeCompileEnd-ShapeCompileStart).count()); if(bIncludeFarWorld&&!bNeighborhoodOnly) StartGpuPipelineStartup(GpuFarPreReservePoolSlots, GpuFarPreReserveCoarseTileCells); bShapePipelineActive=bNeighborhoodOnly; bNeighborhoodReadyReported=false; bFarShapeStagePending=bShapeWorld&&!bNeighborhoodOnly&&!ShapeWorld->hasFarWorld(); std::printf("[ShapeRegion] fine_tiles=%llu bounds=(%d,%d,%d)..(%d,%d,%d) clip=(%d,%d,%d)..(%d,%d,%d)\n", static_cast(FineTiles),Min.X,Min.Y,Min.Z,Max.X,Max.Y,Max.Z, ClipMin.X,ClipMin.Y,ClipMin.Z,ClipMax.X,ClipMax.Y,ClipMax.Z); return true; } bool StartFullShapeBuild(const std::vector& FullDesired,std::string& Error) { FIntVector FineMin(INT32_MAX,INT32_MAX,INT32_MAX),FineMax(INT32_MIN,INT32_MIN,INT32_MIN); FIntVector ClipMin(INT32_MAX,INT32_MAX,INT32_MAX),ClipMax(INT32_MIN,INT32_MIN,INT32_MIN); for(const FVoxelTileKey& Tile:FullDesired) { const FIntVector Origin=Tile.OriginVoxels();const int32 Extent=Tile.ExtentVoxels(); ClipMin.X=std::min(ClipMin.X,Origin.X);ClipMin.Y=std::min(ClipMin.Y,Origin.Y);ClipMin.Z=std::min(ClipMin.Z,Origin.Z); ClipMax.X=std::max(ClipMax.X,Origin.X+Extent);ClipMax.Y=std::max(ClipMax.Y,Origin.Y+Extent);ClipMax.Z=std::max(ClipMax.Z,Origin.Z+Extent); if(Tile.Level>=World->FullResClipLevels)continue; FineMin.X=std::min(FineMin.X,Origin.X);FineMin.Y=std::min(FineMin.Y,Origin.Y);FineMin.Z=std::min(FineMin.Z,Origin.Z); FineMax.X=std::max(FineMax.X,Origin.X+Extent);FineMax.Y=std::max(FineMax.Y,Origin.Y+Extent);FineMax.Z=std::max(FineMax.Z,Origin.Z+Extent); } if(FineMin.X==INT32_MAX||ClipMin.X==INT32_MAX) {Error="the full shape build has no desired detail or clipmap tiles";return false;} PendingFullShapeWorld=std::make_unique(Snapshot); FullShapeBuildError.clear();bFullShapeBuildSucceeded=false; bFullShapeBuildFinished.store(false,std::memory_order_relaxed); const int32 FullWorkers=WorkerCount>=8?6:WorkerCount; FullShapeBuildStart=std::chrono::steady_clock::now(); FullShapeBuildThread=std::thread([this,FineMin,FineMax,ClipMin,ClipMax,FullWorkers, FullDesiredCopy=FullDesired]() { VoxelForgeCore::ShapeBuildRequest Request; Request.minVoxel={FineMin.X,FineMin.Y,FineMin.Z}; Request.maxVoxel={FineMax.X,FineMax.Y,FineMax.Z}; Request.clipMinVoxel={ClipMin.X,ClipMin.Y,ClipMin.Z}; Request.clipMaxVoxel={ClipMax.X,ClipMax.Y,ClipMax.Z}; Request.workerLimit=static_cast(FullWorkers);Request.detail=ShapeDetailVariant; Request.includeFarWorld=true;Request.roundTunnels=bRoundTunnels; Request.enhancedTunnelWalls=bRoundTunnelEnhanced; Request.profileDetailBand=bProfileDetailBand; PopulateGpuVisualDetailBandPlan(Request,FullDesiredCopy); Request.validatePassageRoutes=false; bFullShapeBuildSucceeded=PendingFullShapeWorld->compile( Request,CoreScheduler,FullShapeBuildError); bFullShapeBuildFinished.store(true,std::memory_order_release); }); std::printf("[ShapePipelineBuildStart] neighborhood_tiles=%zu near_mesh_workers=%d full_shape_workers=%d\n", InitialNeighborhoodTiles.size(),WorkerCount>=8?2:1,FullWorkers); std::fflush(stdout); return true; } FStandaloneMeshCacheMetadata MakeMeshCacheMetadata()const { FStandaloneMeshCacheMetadata Metadata; Metadata.SourceDataHash=HashStandaloneFile(DataPath); Metadata.Seed=Seed;Metadata.ClipRadius=ClipRadius; Metadata.FullResClipLevels=World->FullResClipLevels; Metadata.CoarseTileCells=World->CoarseTileCells; Metadata.StrateContentCutMinLevel=World->StrateContentCutMinLevel; Metadata.SkirtCells=World->SkirtCells; Metadata.LODOctaveDrop=World->LODOctaveDrop; Metadata.bGenerateSkirts=World->bGenerateSkirts?1:0; Metadata.AlgorithmVersion=FStandaloneMeshCache::CurrentVersion; Metadata.TunnelMode=bRoundTunnels?(bRoundTunnelEnhanced?2u:1u):0u; return Metadata; } void LoadMeshCache() { MeshCache.Clear(); if(bForceGenerate||bShapeWorld||!World)return; const char* ModeSuffix=!bRoundTunnels?"_base": (bRoundTunnelEnhanced?"_round_detailed":"_round_legacy"); const std::filesystem::path CachePath=std::filesystem::path(DataPath).parent_path() /(std::string("VoxelForge_seed")+std::to_string(Seed)+"_r" +std::to_string(ClipRadius)+ModeSuffix+".vfmesh"); MeshCachePath=CachePath.string(); const auto Begin=std::chrono::steady_clock::now(); std::string CacheError; if(MeshCache.Load(MeshCachePath,MakeMeshCacheMetadata(),CacheError)) { const double Seconds=std::chrono::duration( std::chrono::steady_clock::now()-Begin).count(); std::printf("[MeshCache] loaded %zu tiles, %.2f MiB in %.3f s from %s\n", MeshCache.Num(),static_cast(MeshCache.GetBytesLoaded())/1048576.0, Seconds,MeshCachePath.c_str()); std::fflush(stdout); } else if(CacheError!="cache file is missing or unreadable") std::printf("[MeshCache] ignored %s: %s\n",MeshCachePath.c_str(),CacheError.c_str()); } void StartGeneration() { StopGeneration(); ReleaseMeshes(); GenerationStart=std::chrono::steady_clock::now(); bQuitAfterClipmapClosePosted=false; std::printf("[ColdTimeline] stage=generation_setup begin_ms=%.3f\n", std::chrono::duration(GenerationStart-ColdProcessStart).count()); std::string Error; if(!ConfigureWorld(Error)) { if(GpuPipelineStartupThread.joinable())GpuPipelineStartupThread.join(); std::fprintf(stderr,"World load failed: %s\n",Error.c_str()); MessageBoxA(Window,Error.c_str(),"VoxelForge viewer",MB_ICONERROR);return; } if(GpuPipelineStartupThread.joinable())GpuPipelineStartupThread.join(); std::printf("[ColdTimeline] stage=generation_setup configured_ms=%.3f\n", std::chrono::duration(std::chrono::steady_clock::now()-ColdProcessStart).count()); ResolveGpuWarmupLaunchPolicy(false); const bool bPipelineCanStartNow=!bGpuWarmupDeferredUntilFirstView ||bGpuWarmupDeferredStarted; if(bGpuFarEnabled&&bPipelineCanStartNow&&!EnsureGpuFarPipeline(Error)) {MessageBoxA(Window,Error.c_str(),"VoxelForge GPU pipeline",MB_ICONERROR);return;} if(bGpuFarShaderPrewarm&&!bGpuFarWarmupBeforeWorkers &&!bGpuWarmupDeferredUntilFirstView&&!bGpuWarmupCompleted) StartGpuShaderWarmupAsync(); const FVector CameraVoxels(Position.X*4.0,Position.Y*4.0,Position.Z*4.0); BuildTargetChunk=StandaloneWorldMesher::CameraChunk(CameraVoxels); bFullDetailReported=false;bInitialClipmapReported=false;bWholeViewPresented=false;bAutoCaptureWritten=false; if(bProfileAttribution) { VoxelDensityProfile::SetMode(VoxelDensityProfile::EMode::Attribution,128); VoxelDensityProfile::CalibrateTimer(); VoxelDensityProfile::Reset(); std::printf("Density stage profiling enabled (Attribution, sample interval 128).\n"); } const FStandaloneDesiredTileSet Desired=StandaloneWorldMesher::BuildDesiredSet(*World,CameraVoxels); DesiredTiles=Desired.Tiles; if(ShapeWorld) { const auto CoreTiles=ShapeWorld->desiredTiles({CameraVoxels.X,CameraVoxels.Y,CameraVoxels.Z}); DesiredTiles.clear();DesiredTiles.reserve(CoreTiles.size()); 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(); const V3 F=Forward(),R=Normalize(Cross(F,{0,0,1})),U=Normalize(Cross(R,F)); const double TanHalfFov=std::tan(1.04719755*0.5); const double Aspect=static_cast(Width)/std::max(1,Height); struct FCaptureTileRank { FVoxelTileKey Tile; double Depth=0.0; }; std::vector Visible;Visible.reserve(DesiredTiles.size()); for(const FVoxelTileKey& Tile:DesiredTiles) { const FIntVector Origin=Tile.OriginVoxels(); const double HalfExtent=Tile.ExtentVoxels()*0.8660254037844386; const double DX=Origin.X+Tile.ExtentVoxels()*0.5-CameraVoxels.X; const double DY=Origin.Y+Tile.ExtentVoxels()*0.5-CameraVoxels.Y; const double DZ=Origin.Z+Tile.ExtentVoxels()*0.5-CameraVoxels.Z; const double Depth=DX*F.X+DY*F.Y+DZ*F.Z; if(Depth+HalfExtent<0.0)continue; const double LateralX=std::abs(DX*R.X+DY*R.Y+DZ*R.Z); const double LateralY=std::abs(DX*U.X+DY*U.Y+DZ*U.Z); const double ForwardReach=std::max(1.0,Depth+HalfExtent); if(LateralX>ForwardReach*TanHalfFov*Aspect+HalfExtent ||LateralY>ForwardReach*TanHalfFov+HalfExtent)continue; Visible.push_back({Tile,std::max(0.0,Depth)}); } std::stable_sort(Visible.begin(),Visible.end(),[](const auto& A,const auto& B) {return A.Depthstatic_cast(CaptureTileLimit)) Visible.resize(static_cast(CaptureTileLimit)); DesiredTiles.clear();DesiredTiles.reserve(Visible.size()); for(const FCaptureTileRank& Ranked:Visible)DesiredTiles.push_back(Ranked.Tile); std::printf("[CaptureTileLimit] frustum_tiles=%zu selected=%zu original_desired=%zu limit=%d; reference capture only\n", Visible.size(),DesiredTiles.size(),Before,CaptureTileLimit); } 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; Streamer=std::make_unique(*World,StreamWorkers,false, (!bShapeWorld&&MeshCache.IsLoaded())?&MeshCache:nullptr, bFarShapeStagePending?World->FullResClipLevels-1:-1, false,false,false,false,ShapeWorld.get()); if(bGpuFarTimelineEnabled) Streamer->EnableColdTimelineTrace(ColdProcessStart,&ColdTimelineFrameOrdinal); if(bGpuFarEnabled&&ShapeWorld&&ShapeWorld->hasFarWorld()) { ScheduleGpuFarTiles(DesiredTiles); if(bGpuFarAuditEnabled) { std::vector AuditKeys;AuditKeys.reserve(GpuFarCandidateTiles.size()); for(const FVoxelTileKey& Key:DesiredTiles) if(Key.Level>=6&&std::find(GpuFarCandidateTiles.begin(),GpuFarCandidateTiles.end(),Key) !=GpuFarCandidateTiles.end())AuditKeys.push_back(Key); GpuFarAudit=std::make_unique(*World,*ShapeWorld,AuditKeys,false); } } if(bShapePipelineActive)Streamer->SetDesiredTileFilter(InitialNeighborhoodTiles); else if((CaptureTileLimit>0&&CapturePath.size())||bCaptureOnlyTile) Streamer->SetDesiredTileFilter(DesiredTiles); const FStandaloneStreamingUpdate Update=Streamer->Start(CameraVoxels,{},CrossingIndex); if(bShapePipelineActive&&Update.DesiredTiles!=static_cast(InitialNeighborhoodTiles.size())) { StopGeneration(); Error="the initial neighborhood streamer did not accept all 27 tiles"; std::fprintf(stderr,"World load failed: %s\n",Error.c_str()); return; } FCrossingWork& InitialWork=CrossingWork[CrossingIndex]; InitialWork.SubmittedJobs=Update.NewJobs;InitialWork.PendingJobs=Update.NewJobs; InitialWork.StartTime=GenerationStart; bGenerationRunning=true;bRebuildPending=false; std::printf("[ColdTimeline] stage=cpu_stream_start submitted_ms=%.3f cpu_jobs=%d gpu_queued=%zu\n", std::chrono::duration(std::chrono::steady_clock::now()-ColdProcessStart).count(), Update.NewJobs,GpuFarQueue.size()); const char* TunnelMode=!bRoundTunnels?"":(bRoundTunnelEnhanced ?" with detailed round/winding tunnels":" with legacy round/winding tunnels"); std::printf("Streaming seed %d%s%s: %d desired tiles, %d full-detail tiles, %d workers; upload budget %d batches / %.1f ms per frame.\n", Seed,TunnelMode,bShapeWorld?" [shape intervals]":"",Update.DesiredTiles, Update.FullResTiles,Streamer->GetWorkerCount(),MaxBatchUploadsPerFrame,BatchUploadBudgetMilliseconds); StartGpuFarPreparation(); if(bShapePipelineActive) { std::string ShapeError; if(!StartFullShapeBuild(DesiredTiles,ShapeError)) { StopGeneration(); std::fprintf(stderr,"World load failed: %s\n",ShapeError.c_str()); return; } } std::fflush(stdout); } void RequestSeed(int32 Delta) { const uint32 Next=static_cast(Seed)+static_cast(Delta); Seed=static_cast(Next);bRebuildPending=true; std::printf("Seed changed to %d; replacing the current streaming world.\n",Seed); } void StartFarShapeGeneration() { if(!bFarShapeStagePending||!ShapeWorld||ShapeWorld->hasFarWorld()||!Streamer)return; ShapeWorld->buildFarWorld(); bFarShapeStagePending=false; Streamer->Stop(); std::vector ResidentKeys;ResidentKeys.reserve(ResidentTiles.size()); for(const auto& Pair:ResidentTiles)ResidentKeys.push_back(Pair.first); Streamer.reset(); Streamer=std::make_unique(*World,WorkerCount,false,nullptr,-1, false,false,false,false,ShapeWorld.get()); if(bGpuFarTimelineEnabled) Streamer->EnableColdTimelineTrace(ColdProcessStart,&ColdTimelineFrameOrdinal); if(bGpuFarEnabled) { ScheduleGpuFarTiles(DesiredTiles); if(bGpuFarAuditEnabled&&World) { std::vector AuditKeys;AuditKeys.reserve(GpuFarCandidateTiles.size()); for(const FVoxelTileKey& Key:DesiredTiles) if(Key.Level>=6&&std::find(GpuFarCandidateTiles.begin(),GpuFarCandidateTiles.end(),Key) !=GpuFarCandidateTiles.end())AuditKeys.push_back(Key); GpuFarAudit=std::make_unique(*World,*ShapeWorld,AuditKeys,false); } } const FVector CameraVoxels(Position.X*4.0,Position.Y*4.0,Position.Z*4.0); ++CrossingIndex; const FStandaloneStreamingUpdate Update=Streamer->Start(CameraVoxels,ResidentKeys,CrossingIndex); FCrossingWork& Work=CrossingWork[CrossingIndex]; Work.SubmittedJobs=Update.NewJobs;Work.PendingJobs=Update.NewJobs; Work.StartTime=std::chrono::steady_clock::now(); bGenerationRunning=true; std::printf("[FarStreamStart] desired=%d retained=%d new_jobs=%d workers=%d\n", Update.DesiredTiles,Update.RetainedResidentTiles,Update.NewJobs,WorkerCount); StartGpuFarPreparation(); std::fflush(stdout); } void RecordGpuCrossingTileReady(const FVoxelTileKey& Key) { const auto ReadyAt=std::chrono::steady_clock::now(); for(auto& Pair:CrossingWork) { FCrossingWork& Work=Pair.second; if(Work.bHasNearestNewTile&&Work.NearestNewTile==Key &&Work.NearestReadySeconds<0.0&&Work.StartTime.time_since_epoch().count()!=0) Work.NearestReadySeconds=std::chrono::duration(ReadyAt-Work.StartTime).count(); } } void ReportGpuTileCompletion(const FVoxelTileKey& Key,FGpuFarTile& Tile, uint32 BatchIndex=UINT32_MAX) { if(Tile.CompletedAt.time_since_epoch().count()!=0)return; Tile.CompletedAt=std::chrono::steady_clock::now(); 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), static_cast(ColdTimelineFrame()), ColdTimelineMilliseconds(Tile.SubmittedAt)); std::printf("[GpuTileTimeline] event=uploaded key=(%d,%d,%d,lod%d) batch=%u at_ms=%.3f frame=%llu method=direct_gpu_compute_output copy_upload=none\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level,BatchIndex, ColdTimelineMilliseconds(Tile.CompletedAt), static_cast(ColdTimelineFrame())); } void ReportGpuTileResident(const FVoxelTileKey& Key,FGpuFarTile& Tile) { if(Tile.bColdTimelineResidentReported)return; Tile.bColdTimelineResidentReported=true; const auto ResidentAt=std::chrono::steady_clock::now(); 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), static_cast(ColdTimelineFrame()), ColdTimelineMilliseconds(Tile.SubmittedAt),ColdTimelineMilliseconds(Tile.CompletedAt)); if(Tile.BatchIndex!=UINT32_MAX&&Tile.BatchIndex(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(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(Batch.GpuStartTimestamp) -static_cast(FirstGpuStart))*1000.0/Batch.TimestampFrequency; GpuEndFromFirstMs=(static_cast(Batch.GpuEndTimestamp) -static_cast(FirstGpuStart))*1000.0/Batch.TimestampFrequency; if(PreviousGpuEnd&&PreviousFrequency==Batch.TimestampFrequency) GpuGapBeforeMs=(static_cast(Batch.GpuStartTimestamp) -static_cast(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(Batch.GpuStartTimestamp), static_cast(Batch.GpuEndTimestamp), static_cast(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;} } } bool IsRenderedTileReady(const FVoxelTileKey& Key) { if(bGpuFarEnabled&&ShapeWorld&&ShapeWorld->hasFarWorld() &&GpuFarEligibleTiles.contains(Key)) { auto It=GpuFarTiles.find(Key); if(It==GpuFarTiles.end())return false; FGpuFarTile& Tile=It->second; if(Tile.BatchIndex!=UINT32_MAX&&Tile.BatchIndexGetData(Batch.CompletionEvent,nullptr,0,D3D11_ASYNC_GETDATA_DONOTFLUSH)==S_OK) { std::vector OutputSlots; std::vector BatchOutputKeys; OutputSlots.reserve(Batch.Keys.size()); BatchOutputKeys.reserve(Batch.Keys.size()); for(const FVoxelTileKey& BatchKey:Batch.Keys) { const auto BatchTileIt=GpuFarTiles.find(BatchKey); if(BatchTileIt==GpuFarTiles.end())continue; OutputSlots.push_back(BatchTileIt->second.OutputSlot); BatchOutputKeys.push_back(BatchKey); } std::vector RequiredVertexCounts; std::vector ConnectorOverflowFlags; std::string CountReadbackError; const bool bOutputCountsRead= VoxelForgeGpuFarViewer::ReadFarTileOutputStatuses(Device,Context, GpuFarShaderPath,OutputSlots,RequiredVertexCounts, ConnectorOverflowFlags,CountReadbackError); std::vector OverflowFallbackKeys; if(!bOutputCountsRead) { ++GpuFarOutputCountReadbackFailures; std::fprintf(stderr,"[GpuFarSlotCountReadback] status=FAIL batch=%u tiles=%zu error=%s action=cpu_fallback_batch\n", CurrentBatchIndex,BatchOutputKeys.size(),CountReadbackError.c_str()); OverflowFallbackKeys=BatchOutputKeys; } else { GpuFarOutputCountChecks+=RequiredVertexCounts.size(); for(std::size_t OutputIndex=0;OutputIndexsecond; CheckedTile.RequiredSurfaceVertexCount=Required; if(Required>GpuFarMaxRequiredVertices) { GpuFarMaxRequiredVertices=Required; GpuFarMaxRequiredVertexKey=BatchKey; GpuFarMaxRequiredOutputSlot=CheckedTile.OutputSlot; } if(Required>VoxelForgeGpuFarViewer::PooledOutputVertexCapacityPerTile) { ++GpuFarOutputOverflowCount; OverflowFallbackKeys.push_back(BatchKey); std::fprintf(stderr,"[GpuFarSlotOverflow] key=(%d,%d,%d,lod%d) output_slot=%u required_vertices=%u capacity_vertices=%u batch=%u action=cpu_fallback\n", BatchKey.Coord.X,BatchKey.Coord.Y,BatchKey.Coord.Z,BatchKey.Level, CheckedTile.OutputSlot,Required, VoxelForgeGpuFarViewer::PooledOutputVertexCapacityPerTile,CurrentBatchIndex); } if(OutputIndexsecond.OutputSlot; ReleaseGpuFarTile(FallbackTileIt->second); GpuFarTiles.erase(FallbackTileIt); GpuFarFreeOutputSlots.push_back(ReusableSlot); } if(!OverflowFallbackKeys.empty()) { Batch.TileCount-=static_cast(std::min( Batch.TileCount,OverflowFallbackKeys.size())); AddGpuFarCpuFallbackTiles(OverflowFallbackKeys); } Batch.bGpuComplete=true; const auto PollAt=std::chrono::steady_clock::now(); Batch.CompletedAt=PollAt; const double PollMs=std::chrono::duration(PollAt-ColdProcessStart).count(); if(GpuFarFirstCompletionPollMs<0.0)GpuFarFirstCompletionPollMs=PollMs; GpuFarLastCompletionPollMs=PollMs;++GpuFarCompletionPolls; Batch.CompletionEvent->Release();Batch.CompletionEvent=nullptr; if(bGpuFarTimelineEnabled) { std::printf("[GpuBatchTimeline] event=completed batch=%u at_ms=%.3f frame=%llu tile_count=%u submitted_ms=%.3f\n", CurrentBatchIndex,ColdTimelineMilliseconds(PollAt), static_cast(ColdTimelineFrame()),Batch.TileCount, ColdTimelineMilliseconds(Batch.SubmittedAt)); std::printf("[GpuBatchTimeline] event=uploaded batch=%u at_ms=%.3f frame=%llu method=direct_gpu_compute_output copy_upload=none\n", CurrentBatchIndex,ColdTimelineMilliseconds(PollAt), static_cast(ColdTimelineFrame())); } for(const FVoxelTileKey& BatchKey:Batch.Keys) { auto BatchTileIt=GpuFarTiles.find(BatchKey); if(BatchTileIt!=GpuFarTiles.end()) { BatchTileIt->second.bGpuComplete=true; ReportGpuTileCompletion(BatchKey,BatchTileIt->second,CurrentBatchIndex); RecordGpuCrossingTileReady(BatchKey); ReportGpuTileResident(BatchKey,BatchTileIt->second); } } if(!GpuFarEligibleTiles.contains(Key))return false; } if(Batch.bGpuComplete&&!Batch.bTimingResolved) { if(VoxelForgeGpuFarViewer::ResolveGpuTiming(Context,Batch.TimingQueries, Batch.GpuDispatchMs,&Batch.TimestampFrequency, &Batch.GpuStartTimestamp,&Batch.GpuEndTimestamp)) { Batch.bTimingResolved=true; GpuFarSubmissionSpanMs+=Batch.GpuDispatchMs; GpuFarSubmissionSpanMaxMs=std::max(GpuFarSubmissionSpanMaxMs,Batch.GpuDispatchMs); } } if(Batch.bGpuComplete&&Batch.bTimingResolved&&!Tile.bTimingResolved &&Batch.TimestampFrequency) { double TileDispatchMs=0.0; if(VoxelForgeGpuFarViewer::ResolveGpuTimestampPair(Context,Tile.TimingQueries, Batch.TimestampFrequency,TileDispatchMs)) { Tile.GpuDispatchMs=TileDispatchMs;Tile.bTimingResolved=true; ReportGpuFarSlowDispatchTile(Key,Tile,TileDispatchMs); GpuFarGpuDispatchMs+=TileDispatchMs; if(TileDispatchMs>GpuFarGpuDispatchMaxMs) { GpuFarGpuDispatchMaxMs=TileDispatchMs; GpuFarGpuDispatchMaxKey=Key;bGpuFarGpuDispatchMaxKeyValid=true; } } } if(Batch.bGpuComplete) { RecordGpuCrossingTileReady(Key); ReportGpuTileResident(Key,Tile); } return Batch.bGpuComplete; } if(!Tile.bGpuComplete&&Tile.CompletionEvent&&Context &&Context->GetData(Tile.CompletionEvent,nullptr,0,D3D11_ASYNC_GETDATA_DONOTFLUSH)==S_OK) { std::vector RequiredVertexCounts; std::vector ConnectorOverflowFlags; std::string CountReadbackError; const bool bOutputCountRead=VoxelForgeGpuFarViewer::ReadFarTileOutputStatuses( Device,Context,GpuFarShaderPath,{Tile.OutputSlot},RequiredVertexCounts, ConnectorOverflowFlags,CountReadbackError); const bool bOverflow=!bOutputCountRead||RequiredVertexCounts.empty() ||RequiredVertexCounts[0]>VoxelForgeGpuFarViewer::PooledOutputVertexCapacityPerTile ||ConnectorOverflowFlags.empty()||ConnectorOverflowFlags[0]!=0; if(!bOutputCountRead) { ++GpuFarOutputCountReadbackFailures; std::fprintf(stderr,"[GpuFarSlotCountReadback] status=FAIL key=(%d,%d,%d,lod%d) output_slot=%u error=%s action=cpu_fallback\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level,Tile.OutputSlot, CountReadbackError.c_str()); } else if(!RequiredVertexCounts.empty()) { const uint32 Required=RequiredVertexCounts[0]; ++GpuFarOutputCountChecks;Tile.RequiredSurfaceVertexCount=Required; if(Required>GpuFarMaxRequiredVertices) { GpuFarMaxRequiredVertices=Required;GpuFarMaxRequiredVertexKey=Key; GpuFarMaxRequiredOutputSlot=Tile.OutputSlot; } if(Required>VoxelForgeGpuFarViewer::PooledOutputVertexCapacityPerTile) { ++GpuFarOutputOverflowCount; std::fprintf(stderr,"[GpuFarSlotOverflow] key=(%d,%d,%d,lod%d) output_slot=%u required_vertices=%u capacity_vertices=%u action=cpu_fallback\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level,Tile.OutputSlot,Required, VoxelForgeGpuFarViewer::PooledOutputVertexCapacityPerTile); } if(!ConnectorOverflowFlags.empty()&&ConnectorOverflowFlags[0]!=0) { ++GpuFarConnectorOverflowCount; std::fprintf(stderr,"[GpuFarPanelOverflow] key=(%d,%d,%d,lod%d) output_slot=%u action=cpu_fallback\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level,Tile.OutputSlot); } } if(bOverflow) { const uint32 ReusableSlot=Tile.OutputSlot; GpuFarEligibleTiles.erase(Key);GpuFarPreparedInputs.erase(Key); GpuFarPreparationErrors.erase(Key);GpuFarPreparedAt.erase(Key); ReleaseGpuFarPanelOutputRange(Key); ReleaseGpuFarTile(Tile);GpuFarTiles.erase(Key); GpuFarFreeOutputSlots.push_back(ReusableSlot); AddGpuFarCpuFallbackTiles({Key}); return false; } Tile.bGpuComplete=true; Tile.CompletionEvent->Release();Tile.CompletionEvent=nullptr; ReportGpuTileCompletion(Key,Tile); } if(Tile.bGpuComplete&&!Tile.bTimingResolved) { double AsyncDispatchMs=0.0; if(VoxelForgeGpuFarViewer::ResolveGpuTiming(Context,Tile.TimingQueries,AsyncDispatchMs)) { if(Tile.GpuDispatchMs==0.0) { Tile.GpuDispatchMs=AsyncDispatchMs; ReportGpuFarSlowDispatchTile(Key,Tile,AsyncDispatchMs); GpuFarGpuDispatchMs+=AsyncDispatchMs; if(AsyncDispatchMs>GpuFarGpuDispatchMaxMs) { GpuFarGpuDispatchMaxMs=AsyncDispatchMs; GpuFarGpuDispatchMaxKey=Key;bGpuFarGpuDispatchMaxKeyValid=true; } } Tile.bTimingResolved=true; } } if(Tile.bGpuComplete) { RecordGpuCrossingTileReady(Key); ReportGpuTileResident(Key,Tile); } return Tile.bGpuComplete; } return ResidentTiles.contains(Key); } void PrepareGpuFarInputTile(const FVoxelTileKey& Key,uint8 VisibleSkirtFaceMask, const std::shared_ptr& Batch) { if(Batch->bCancelled.load(std::memory_order_acquire))return; std::call_once(Batch->StartOnce,[&]() { Batch->PrepareStart=std::chrono::steady_clock::now(); if(bGpuFarTimelineEnabled) std::printf("[ColdTimeline] event=gpu_input_export_workers_started at_ms=%.3f dispatch_to_start_ms=%.3f cpu_ready_to_start_ms=%.3f frame=%llu shared_workers=%zu\n", ColdTimelineMilliseconds(Batch->PrepareStart), std::chrono::duration( Batch->PrepareStart-Batch->DispatchAt).count(), Batch->CpuReadyAt.time_since_epoch().count()!=0 ?std::chrono::duration( Batch->PrepareStart-Batch->CpuReadyAt).count():-1.0, static_cast(ColdTimelineFrame()), Batch->SharedWorkerCount); std::printf("[ColdTimeline] stage=gpu_input_export begin_ms=%.3f tiles=%zu shared_workers=%zu\n", ColdTimelineMilliseconds(Batch->PrepareStart),Batch->TileCount, Batch->SharedWorkerCount); }); const auto WorkerStart=std::chrono::steady_clock::now(); const VoxelForgeCore::TileKey CoreKey{{Key.Coord.X,Key.Coord.Y,Key.Coord.Z},Key.Level}; FPreparedGpuFarInputResult Result;Result.Key=Key; try { Result.Input=Key.LevelFullResClipLevels ?ShapeWorld->exportGpuFieldTile(CoreKey,Result.Error) :ShapeWorld->exportFarFieldTile(CoreKey,Result.Error); if(Result.Input&&VisibleSkirtFaceMask!=0) { Result.Input->visibleSkirtFaceMask=VisibleSkirtFaceMask; Result.Input->skirtDepthVoxels=std::max(1.0f, static_cast(World->SkirtCells))*Result.Input->step; } if(Result.Input&&Key.Level>=World->FullResClipLevels) { if(!bGpuConnectorRepairEnabled) { Result.Input->connectorPanels.clear(); Result.Input->connectorRingCount=0; Result.Input->connectorVertexCount=0; } } } catch(const std::exception& Error) { Result.Error=Error.what(); } catch(...) { Result.Error="unknown input preparation failure"; } if(Batch->bCancelled.load(std::memory_order_acquire)) { Batch->Remaining.fetch_sub(1,std::memory_order_relaxed); return; } Result.FinishedAt=std::chrono::steady_clock::now(); Result.FinishedFrame=ColdTimelineFrame(); if(!Result.Input)Batch->Failed.fetch_add(1,std::memory_order_relaxed); const uint64 WorkerNanoseconds=static_cast(std::chrono::duration_cast< std::chrono::nanoseconds>(Result.FinishedAt-WorkerStart).count()); Batch->WorkerNanoseconds.fetch_add(WorkerNanoseconds,std::memory_order_relaxed); { std::lock_guard Lock(GpuFarPreparedResultsMutex); if(Batch->bCancelled.load(std::memory_order_acquire) ||Batch->Generation!=GpuFarPreparationGeneration.load(std::memory_order_acquire)) { Batch->Remaining.fetch_sub(1,std::memory_order_relaxed); return; } GpuFarPreparedResults.push_back(std::move(Result)); } if(Batch->Remaining.fetch_sub(1,std::memory_order_acq_rel)==1) { const auto PrepareEnd=std::chrono::steady_clock::now(); const double PreparationMs=std::chrono::duration( PrepareEnd-Batch->PrepareStart).count(); const double WorkerSumMs=static_cast( Batch->WorkerNanoseconds.load(std::memory_order_relaxed))/1.0e6; GpuFarPreparationWallMs+=PreparationMs; GpuFarPreparationWorkerMs+=WorkerSumMs; std::printf("[GpuFarInputPrepare] tiles=%zu workers=%zu mode=shared_priority_queue wall_ms=%.3f worker_sum_ms=%.3f failed=%zu\n", Batch->TileCount,Batch->SharedWorkerCount,PreparationMs,WorkerSumMs, Batch->Failed.load(std::memory_order_relaxed)); std::printf("[ColdTimeline] stage=gpu_input_export end_ms=%.3f duration_ms=%.3f worker_sum_ms=%.3f\n", ColdTimelineMilliseconds(PrepareEnd),PreparationMs,WorkerSumMs); std::fflush(stdout); std::lock_guard Lock(GpuFarPreparedResultsMutex); if(!Batch->bCancelled.load(std::memory_order_acquire) &&Batch->Generation==GpuFarPreparationGeneration.load(std::memory_order_acquire)) bGpuFarPreparationFinished.store(true,std::memory_order_release); } } void ReportGpuFarSlowDispatchTile(const FVoxelTileKey& Key,const FGpuFarTile& Tile, double DispatchMs)const { if(!bGpuFarTimelineEnabled||DispatchMs<5.0)return; std::printf("[GpuFarSlowDispatchTile] key=(%d,%d,%d,lod%d) dispatch_ms=%.6f output_slot=%u output_chunk=%u cells=%d step=%d near_detail=%d protected=%llu thin=%llu solid=%llu near_proxy_samples=%u skirt_faces=0x%02x connector_rings=%u connector_vertices=%u\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level,DispatchMs,Tile.OutputSlot, Tile.OutputSlot/VoxelForgeGpuFarViewer::PooledOutputSlotsPerChunk,Tile.InputCells, Tile.InputStep,Tile.bNearDetailInput?1:0, static_cast(Tile.ProtectedSamples), static_cast(Tile.ProtectedThinSamples), static_cast(Tile.ProtectedSolidSamples),Tile.NearProxySamples, static_cast(Tile.VisibleSkirtFaceMask),Tile.ConnectorRings, Tile.ConnectorVertices); } void CoalesceGpuFarPanelOutputFreeRanges() { std::sort(GpuFarPanelOutputFreeRanges.begin(),GpuFarPanelOutputFreeRanges.end(), [](const FGpuFarPanelFreeRange& A,const FGpuFarPanelFreeRange& B) {return A.BaseVertex Merged; Merged.reserve(GpuFarPanelOutputFreeRanges.size()); for(const FGpuFarPanelFreeRange& Range:GpuFarPanelOutputFreeRanges) { if(Range.CapacityVertices==0)continue; if(!Merged.empty()&&static_cast(Merged.back().BaseVertex) +Merged.back().CapacityVertices==Range.BaseVertex) Merged.back().CapacityVertices+=Range.CapacityVertices; else Merged.push_back(Range); } GpuFarPanelOutputFreeRanges=std::move(Merged); while(!GpuFarPanelOutputFreeRanges.empty()) { const FGpuFarPanelFreeRange& Last=GpuFarPanelOutputFreeRanges.back(); if(static_cast(Last.BaseVertex)+Last.CapacityVertices !=GpuFarPanelOutputHighWater)break; GpuFarPanelOutputHighWater=Last.BaseVertex; GpuFarPanelOutputFreeRanges.pop_back(); } } void ReleaseGpuFarPanelOutputRange(const FVoxelTileKey& Key) { const auto It=GpuFarPanelOutputRanges.find(Key); if(It==GpuFarPanelOutputRanges.end())return; if(It->second.CapacityVertices!=0) GpuFarPanelOutputFreeRanges.push_back({It->second.BaseVertex,It->second.CapacityVertices}); GpuFarPanelOutputRanges.erase(It); CoalesceGpuFarPanelOutputFreeRanges(); } bool AllocateGpuFarPanelOutputRange(std::uint32_t CapacityVertices, FGpuFarPanelOutputRange& Out) { if(CapacityVertices==0){Out={};return true;} for(auto It=GpuFarPanelOutputFreeRanges.begin();It!=GpuFarPanelOutputFreeRanges.end();++It) { if(It->CapacityVerticesBaseVertex,CapacityVertices}; It->BaseVertex+=CapacityVertices; It->CapacityVertices-=CapacityVertices; if(It->CapacityVertices==0)GpuFarPanelOutputFreeRanges.erase(It); return true; } if(static_cast(GpuFarPanelOutputHighWater)+CapacityVertices >std::numeric_limits::max())return false; Out={GpuFarPanelOutputHighWater,CapacityVertices}; GpuFarPanelOutputHighWater+=CapacityVertices; return true; } bool ReserveGpuFarPanelOutputPool(std::string& Error) { for(auto It=GpuFarPanelOutputRanges.begin();It!=GpuFarPanelOutputRanges.end();) { if(GpuFarEligibleTiles.contains(It->first)){++It;continue;} const FVoxelTileKey Key=It->first;++It; ReleaseGpuFarPanelOutputRange(Key); } for(const FVoxelTileKey& Key:GpuFarQueue) { const auto InputIt=GpuFarPreparedInputs.find(Key); if(InputIt==GpuFarPreparedInputs.end()) {Error="prepared input is missing while reserving its panel output";return false;} const VoxelForgeCore::FarFieldTileInput& Input=InputIt->second; const uint64 RequiredCapacity64=static_cast(Input.connectorVertexCount) +(Input.visibleSkirtFaceMask!=0 ?VoxelForgeGpuFarViewer::NearSkirtOutputVertexCapacityPerTile:0u); if(RequiredCapacity64>std::numeric_limits::max()) {Error="per-tile panel output capacity exceeds the 32-bit vertex limit";return false;} const uint32 RequiredCapacity=static_cast(RequiredCapacity64); auto RangeIt=GpuFarPanelOutputRanges.find(Key); if(RangeIt!=GpuFarPanelOutputRanges.end() &&RangeIt->second.CapacityVertices>=RequiredCapacity)continue; if(RangeIt!=GpuFarPanelOutputRanges.end())ReleaseGpuFarPanelOutputRange(Key); FGpuFarPanelOutputRange Range{}; if(!AllocateGpuFarPanelOutputRange(RequiredCapacity,Range)) {Error="panel output pool exceeds the 32-bit vertex limit";return false;} GpuFarPanelOutputRanges.emplace(Key,Range); } if(!VoxelForgeGpuFarViewer::ReserveFarOutputPool(Device,Context,GpuFarShaderPath, GpuFarOutputCapacitySlots,static_cast(World->CoarseTileCells),Error, GpuFarPanelOutputHighWater))return false; GpuFarOutputPoolReservedSlots=std::max(GpuFarOutputPoolReservedSlots, GpuFarOutputCapacitySlots); GpuFarPanelOutputReservedCapacityVertices=std::max( GpuFarPanelOutputReservedCapacityVertices,GpuFarPanelOutputHighWater); std::printf("[GpuPanelOutputPool] queued_tiles=%zu live_ranges=%zu capacity_vertices=%u high_water=%u status=reserved\n", GpuFarQueue.size(),GpuFarPanelOutputRanges.size(), GpuFarPanelOutputReservedCapacityVertices,GpuFarPanelOutputHighWater); return true; } void ScheduleGpuFarTiles(const std::vector& Keys) { if(GpuFarPreparationState) GpuFarPreparationState->bCancelled.store(true,std::memory_order_release); if(Streamer)Streamer->ClearPriorityTasks(); GpuFarPreparationState.reset(); { std::lock_guard Lock(GpuFarPreparedResultsMutex); GpuFarPreparationGeneration.fetch_add(1,std::memory_order_acq_rel); GpuFarPreparedResults.clear(); } GpuFarQueue.clear();GpuFarQueued.clear();GpuFarEligibleTiles.clear(); GpuFarPreparedInputs.clear();GpuFarPreparationErrors.clear();GpuFarPreparedAt.clear(); 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; if(!bGpuFarEnabled||!ShapeWorld||!ShapeWorld->hasFarWorld())return; std::vector CpuTiles;CpuTiles.reserve(Keys.size()); std::vector Eligible;Eligible.reserve(Keys.size()); uint64 NearGpuSkirtTiles=0,SkirtTransitionFallbackTiles=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.LevelFullResClipLevels; if(NearGpuEligible||ShapeWorld->isFarFieldTileEligible(CoreKey)) { const uint8 VisibleSkirtFaces=World->bGenerateSkirts ?ComputeVisibleSkirtFaceMask(Key,DesiredTileSet):0; if(Key.Level>=World->FullResClipLevels) { 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&&!bGpuNearSkirtsEnabled) { // Keep the costly near skirt tiles on CPU; measured GPU savings did not cover their input and dispatch cost. CpuTiles.push_back(Key); ++SkirtTransitionFallbackTiles; } else { if(VisibleSkirtFaces!=0&&NearGpuEligible)++NearGpuSkirtTiles; 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"); } const std::unordered_set CurrentEligible( Eligible.begin(),Eligible.end()); for(auto It=GpuFarPanelOutputRanges.begin();It!=GpuFarPanelOutputRanges.end();) { if(CurrentEligible.contains(It->first)){++It;continue;} const FVoxelTileKey Key=It->first;++It; ReleaseGpuFarPanelOutputRange(Key); } for(auto It=GpuFarTiles.begin();It!=GpuFarTiles.end();) { if(CurrentEligible.contains(It->first)){++It;continue;} GpuFarFreeOutputSlots.push_back(It->second.OutputSlot); ReleaseGpuFarTile(It->second); It=GpuFarTiles.erase(It); } if(Eligible.size()>GpuFarOutputCapacitySlots) { for(auto& Pair:GpuFarTiles)ReleaseGpuFarTile(Pair.second); GpuFarTiles.clear();GpuFarFreeOutputSlots.clear();GpuFarNextOutputSlot=0; GpuFarOutputCapacitySlots=static_cast(Eligible.size()); } if(!Eligible.empty()&&GpuFarOutputCapacitySlots==0) GpuFarOutputCapacitySlots=static_cast(Eligible.size()); if(bCaptureOnlyTile&&CaptureOutputSlot>=0) { GpuFarOutputCapacitySlots=std::max(GpuFarOutputCapacitySlots, static_cast(CaptureOutputSlot+1)); GpuFarNextOutputSlot=static_cast(CaptureOutputSlot); std::printf("[CaptureOutputSlotProbe] slot=%d pool_slots=%u\n", CaptureOutputSlot,GpuFarOutputCapacitySlots); } GpuFarCandidateTiles=std::move(Eligible); GpuFarBaseCpuFallbackTiles=CpuTiles; GpuFarCpuFallbackTiles=std::move(CpuTiles); 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()); GpuFarCpuFallbackTiles.insert(GpuFarCpuFallbackTiles.end(), GpuFarCandidateTiles.begin(),GpuFarCandidateTiles.end()); } GpuFarNeedPreparation.reserve(GpuFarCandidateTiles.size()); for(const FVoxelTileKey& Key:GpuFarCandidateTiles) if(!GpuFarTiles.contains(Key))GpuFarNeedPreparation.push_back(Key); if(Streamer)Streamer->SetDesiredTileFilter(GpuFarCpuFallbackTiles); const std::size_t NearGpuTiles=static_cast(std::count_if( GpuFarCandidateTiles.begin(),GpuFarCandidateTiles.end(),[&](const FVoxelTileKey& Key) {return Key.LevelFullResClipLevels;})); std::printf("[GpuFieldEligibility] candidate_gpu_tiles=%zu near_gpu_tiles=%zu cpu_fallback_tiles=%zu warmup_cpu_fallback=%s\n", GpuFarCandidateTiles.size(),NearGpuTiles,GpuFarCpuFallbackTiles.size(), bGpuWarmupRoutePending?"yes":"no"); std::printf("[GpuSkirtSeamRouting] near_skirt_gpu_tiles=%llu near_cpu_fallback_tiles=%llu\n", static_cast(NearGpuSkirtTiles), static_cast(SkirtTransitionFallbackTiles)); } void AddGpuFarCpuFallbackTiles(const std::vector& Additional) { if(Additional.empty()||!Streamer)return; std::unordered_set Seen( GpuFarCpuFallbackTiles.begin(),GpuFarCpuFallbackTiles.end()); std::size_t Added=0; for(const FVoxelTileKey& Key:Additional) if(Seen.insert(Key).second){GpuFarCpuFallbackTiles.push_back(Key);++Added;} if(Added==0)return; Streamer->SetDesiredTileFilter(GpuFarCpuFallbackTiles); const FVector CameraVoxels(Position.X*4.0,Position.Y*4.0,Position.Z*4.0); std::vector ResidentKeys;ResidentKeys.reserve(ResidentTiles.size()); for(const auto& Pair:ResidentTiles)ResidentKeys.push_back(Pair.first); const FStandaloneStreamingUpdate Update=Streamer->UpdateDesired( CameraVoxels,ResidentKeys,CrossingIndex); FCrossingWork& Work=CrossingWork[CrossingIndex]; Work.SubmittedJobs+=Update.NewJobs;Work.PendingJobs+=Update.NewJobs; std::printf("[GpuFarPrepFallbackAdded] tiles=%zu queued_jobs=%d cpu_fallback_total=%zu\n", Added,Update.NewJobs,GpuFarCpuFallbackTiles.size()); } 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(World->CoarseTileCells),PoolError,0)) { std::fprintf(stderr,"[GpuFarPoolError] %s\n",PoolError.c_str()); bGpuFarEnabled=false;bGpuFarPreparationStarted=true; GpuFarOutputCapacitySlots=0;GpuFarOutputPoolReservedSlots=0; GpuFarPanelOutputReservedCapacityVertices=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( 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) { 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; const auto PoolEnd=std::chrono::steady_clock::now(); const auto MemorySampleStart=std::chrono::steady_clock::now(); SampleGpuFarMemory(); const double MemorySampleMs=std::chrono::duration( std::chrono::steady_clock::now()-MemorySampleStart).count(); if(GpuFarNeedPreparation.empty()) { bGpuFarPreparationFinished.store(true,std::memory_order_relaxed); return; } const auto PreparationListStart=std::chrono::steady_clock::now(); std::vector NeedPreparation=GpuFarNeedPreparation; std::stable_sort(NeedPreparation.begin(),NeedPreparation.end(), [&](const FVoxelTileKey& A,const FVoxelTileKey& B){return GpuFarKeyLess(A,B);}); const double PreparationListMs=std::chrono::duration( std::chrono::steady_clock::now()-PreparationListStart).count(); const auto DispatchAt=std::chrono::steady_clock::now(); auto Batch=std::make_shared(); Batch->DispatchAt=DispatchAt;Batch->TileCount=NeedPreparation.size(); Batch->CpuReadyAt=CpuReadyFrameBeforeGpuAt; Batch->SharedWorkerCount=Streamer?static_cast(Streamer->GetWorkerCount()):0; Batch->Generation=GpuFarPreparationGeneration.load(std::memory_order_acquire); Batch->Remaining.store(NeedPreparation.size(),std::memory_order_relaxed); GpuFarPreparationState=Batch; bGpuFarPreparationFinished.store(false,std::memory_order_relaxed); if(bGpuFarTimelineEnabled) std::printf("[ColdTimeline] event=gpu_input_export_priority_queue at_ms=%.3f after_pool_ms=%.3f cpu_ready_to_queue_ms=%.3f memory_sample_ms=%.3f list_copy_sort_ms=%.3f tiles=%zu shared_workers=%zu\n", ColdTimelineMilliseconds(DispatchAt), std::chrono::duration(DispatchAt-PoolEnd).count(), CpuReadyFrameBeforeGpuAt.time_since_epoch().count()!=0 ?std::chrono::duration(DispatchAt-CpuReadyFrameBeforeGpuAt).count():-1.0, MemorySampleMs,PreparationListMs,NeedPreparation.size(),Batch->SharedWorkerCount); constexpr std::size_t GpuInputPriorityBurst=3; std::printf("[GpuFarSchedulingPolicy] workers=%zu gpu_input_priority_burst=%zu cpu_mesh_jobs_per_burst=1 mode=shared_worker_pool\n", Batch->SharedWorkerCount,GpuInputPriorityBurst); std::vector> Tasks;Tasks.reserve(NeedPreparation.size()); for(const FVoxelTileKey& Key:NeedPreparation) { const uint8 VisibleSkirtFaceMask=World->bGenerateSkirts&&bGpuNearSkirtsEnabled ?ComputeVisibleSkirtFaceMask(Key,DesiredTileSet):0; Tasks.emplace_back([this,Key,VisibleSkirtFaceMask,Batch]() {PrepareGpuFarInputTile(Key,VisibleSkirtFaceMask,Batch);}); } if(!Streamer||!Streamer->QueuePriorityTasks(std::move(Tasks))) { std::fprintf(stderr,"[GpuFarInputPrepareError] shared worker queue is unavailable\n"); GpuFarPreparationState.reset();bGpuFarEnabled=false; bGpuFarInputsFinalized=true; bGpuFarPreparationFinished.store(true,std::memory_order_release); AddGpuFarCpuFallbackTiles(DesiredTiles); } } bool GpuFarKeyLess(const FVoxelTileKey& A,const FVoxelTileKey& B)const { if(A.Level!=B.Level)return A.Level(ObservedAt-CpuReadyFrameBeforeGpuAt).count():-1.0; std::printf("[ColdTimeline] event=gpu_warmup_completion_observed at_ms=%.3f queue_finished_at_ms=%.3f observe_delay_ms=%.3f cpu_ready_frame_presented=%s cpu_ready_to_observed_ms=%.3f frame=%llu\n", ColdTimelineMilliseconds(ObservedAt),ColdTimelineMilliseconds(GpuShaderWarmupQueueFinishedAt), std::chrono::duration(ObservedAt-GpuShaderWarmupQueueFinishedAt).count(), CpuReadyFrameBeforeGpuAt.time_since_epoch().count()!=0?"yes":"no", CpuReadyToObservedMs,static_cast(ColdTimelineFrame())); } const auto WarmupStart=std::chrono::steady_clock::now(); if(GpuShaderWarmupThread.joinable())GpuShaderWarmupThread.join(); if(!bGpuShaderWarmupQueueSucceeded) { std::fprintf(stderr,"[GpuShaderWarmupError] queue: %s\n", GpuShaderWarmupQueueError.empty()?"warmup queue failed":GpuShaderWarmupQueueError.c_str()); bGpuFarEnabled=false;bGpuWarmupRoutePending=false; SetGpuWarmupContextProtection(false); AddGpuFarCpuFallbackTiles(DesiredTiles); return false; } std::string WarmupError; if(!VoxelForgeGpuFarViewer::CompleteFarShaderWarmup(Device,Context, GpuFarShaderPath,WarmupError)) { std::fprintf(stderr,"[GpuShaderWarmupError] %s\n",WarmupError.c_str()); bGpuFarEnabled=false;bGpuWarmupRoutePending=false; SetGpuWarmupContextProtection(false); AddGpuFarCpuFallbackTiles(DesiredTiles); return false; } bGpuWarmupCompleted=true; MarkGpuWarmupCacheReady(); SetGpuWarmupContextProtection(false); std::printf("[GpuShaderWarmupComplete] completion_wall_ms=%.3f\n", std::chrono::duration( std::chrono::steady_clock::now()-WarmupStart).count()); if(!bGpuWarmupRoutePending||!Streamer)return true; std::vector ResidentKeys;ResidentKeys.reserve(ResidentTiles.size()); for(const auto& Pair:ResidentTiles)ResidentKeys.push_back(Pair.first); std::vector RetainedCandidates; const FStandaloneStreamingUpdate Update=Streamer->RestrictDesiredTileFilterKeepingStarted( GpuFarBaseCpuFallbackTiles,GpuFarCandidateTiles,ResidentKeys,RetainedCandidates); for(const auto& Pair:Update.CancelledByCrossing) { auto WorkIt=CrossingWork.find(Pair.first); if(WorkIt==CrossingWork.end())continue; FCrossingWork& Work=WorkIt->second; Work.PendingJobs=Work.PendingJobs>=Pair.second?Work.PendingJobs-Pair.second:0; Work.CancelledQueuedJobs+=Pair.second; } std::unordered_set CpuOwned( RetainedCandidates.begin(),RetainedCandidates.end()); const std::size_t CandidateCountBefore=GpuFarCandidateTiles.size(); GpuFarCandidateTiles.erase(std::remove_if(GpuFarCandidateTiles.begin(),GpuFarCandidateTiles.end(), [&](const FVoxelTileKey& Key){return CpuOwned.contains(Key);}),GpuFarCandidateTiles.end()); GpuFarNeedPreparation.erase(std::remove_if(GpuFarNeedPreparation.begin(),GpuFarNeedPreparation.end(), [&](const FVoxelTileKey& Key){return CpuOwned.contains(Key);}),GpuFarNeedPreparation.end()); GpuFarCpuFallbackTiles=GpuFarBaseCpuFallbackTiles; GpuFarCpuFallbackTiles.insert(GpuFarCpuFallbackTiles.end(), RetainedCandidates.begin(),RetainedCandidates.end()); GpuFarWarmupCpuClaimedTiles=RetainedCandidates.size(); GpuFarWarmupGpuTakeoverTiles=GpuFarCandidateTiles.size(); bGpuWarmupRoutePending=false; const bool bHandoffValid=RetainedCandidates.size()+GpuFarCandidateTiles.size()==CandidateCountBefore; std::printf("[GpuWarmupHandoff] cpu_started_ready_or_resident=%zu gpu_takeover_unstarted=%zu cancelled_cpu_queue_jobs=%d cpu_filter_tiles=%zu status=%s\n", RetainedCandidates.size(),GpuFarCandidateTiles.size(),Update.CancelledQueuedJobs, GpuFarCpuFallbackTiles.size(),bHandoffValid?"PASS":"FAIL"); return true; } bool FinalizeGpuFarPreparation() { if(bGpuFarInputsFinalized)return true; if(!bGpuFarPreparationStarted)return false; std::deque ReadyResults; { std::lock_guard Lock(GpuFarPreparedResultsMutex); ReadyResults.swap(GpuFarPreparedResults); } std::vector Failed; bool bQueueChanged=false; for(FPreparedGpuFarInputResult& Result:ReadyResults) { const FVoxelTileKey& Key=Result.Key; if(Result.Input) { if(Result.Input->nearDetailEnabled) { ++GpuFarPreparedNearTileInputs; GpuFarNearLatticeSamples+=Result.Input->nearPackedProxy.size(); GpuFarNearPackedCandidateSamples+=Result.Input->nearPackedCandidateSampleCount; GpuFarNearPackedSkippedSamples+=Result.Input->nearPackedSkippedSampleCount; } else ++GpuFarPreparedFarTileInputs; GpuFarProtectedRouteSamples+=Result.Input->protectedSampleCount; GpuFarProtectedThinSamples+=Result.Input->protectedThinSampleCount; GpuFarProtectedSolidSamples+=Result.Input->protectedSolidSampleCount; GpuFarProtectedSealSamples+=Result.Input->protectedSealSampleCount; GpuFarProtectedOverlaySamples+=Result.Input->protectedSolidOverlaySampleCount; GpuFarPreparedInputs.emplace(Key,std::move(*Result.Input)); GpuFarPreparedAt.emplace(Key,Result.FinishedAt); GpuFarEligibleTiles.insert(Key); if(!GpuFarTiles.contains(Key)&&GpuFarQueued.insert(Key).second) { GpuFarQueue.push_back(Key); bQueueChanged=true; } if(bGpuFarTimelineEnabled) std::printf("[GpuTileTimeline] event=prepared key=(%d,%d,%d,lod%d) at_ms=%.3f frame=%llu\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level, ColdTimelineMilliseconds(Result.FinishedAt), static_cast(Result.FinishedFrame)); if(!bGpuFarFirstPreparedInputReported) { bGpuFarFirstPreparedInputReported=true; std::printf("[ColdTimeline] event=gpu_first_input_ready key=(%d,%d,%d,lod%d) at_ms=%.3f\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level, ColdTimelineMilliseconds(Result.FinishedAt)); } } else { GpuFarPreparationErrors.emplace(Key,Result.Error.empty() ?"far-field input export failed":std::move(Result.Error)); Failed.push_back(Key); } } if(bQueueChanged)SortGpuFarQueue(); if(!Failed.empty()) { for(const FVoxelTileKey& Key:Failed) { const auto Error=GpuFarPreparationErrors.find(Key); std::fprintf(stderr,"[GpuFieldInputFallback] key=(%d,%d,%d,lod%d) reason=%s\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level, Error==GpuFarPreparationErrors.end()?"far-field input export failed":Error->second.c_str()); } AddGpuFarCpuFallbackTiles(Failed); } if(!bGpuFarPreparationFinished.load(std::memory_order_acquire)) return !GpuFarQueue.empty(); if(!bGpuFarEnabled) { GpuFarCandidateTiles.clear();GpuFarQueue.clear();GpuFarQueued.clear(); GpuFarEligibleTiles.clear(); for(auto& Pair:GpuFarTiles)ReleaseGpuFarTile(Pair.second); GpuFarTiles.clear(); AddGpuFarCpuFallbackTiles(DesiredTiles); bGpuFarInputsFinalized=true; return false; } for(const FVoxelTileKey& Key:GpuFarCandidateTiles) { if(GpuFarTiles.contains(Key)) {GpuFarEligibleTiles.insert(Key);continue;} if(GpuFarEligibleTiles.contains(Key)||GpuFarPreparationErrors.contains(Key))continue; if(!GpuFarPreparedInputs.contains(Key)) { Failed.push_back(Key); const auto Error=GpuFarPreparationErrors.find(Key); std::fprintf(stderr,"[GpuFieldInputFallback] key=(%d,%d,%d,lod%d) reason=%s\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level, Error==GpuFarPreparationErrors.end()?"missing prepared input":Error->second.c_str()); continue; } GpuFarEligibleTiles.insert(Key); if(GpuFarQueued.insert(Key).second)GpuFarQueue.push_back(Key); } if(!GpuFarQueue.empty())SortGpuFarQueue(); AddGpuFarCpuFallbackTiles(Failed); std::string PanelPoolError; if(!ReserveGpuFarPanelOutputPool(PanelPoolError)) { std::fprintf(stderr,"[GpuFarPoolError] panel-output reservation failed: %s\n", PanelPoolError.c_str()); bGpuFarEnabled=false;GpuFarQueue.clear();GpuFarQueued.clear(); GpuFarEligibleTiles.clear(); AddGpuFarCpuFallbackTiles(DesiredTiles); bGpuFarInputsFinalized=true; return false; } bGpuFarInputsFinalized=true; const std::size_t NearGpuTiles=static_cast(std::count_if( GpuFarEligibleTiles.begin(),GpuFarEligibleTiles.end(),[&](const FVoxelTileKey& Key) {return Key.LevelFullResClipLevels;})); std::printf("[GpuFieldEligibility] eligible_gpu_tiles=%zu near_gpu_tiles=%zu cpu_fallback_tiles=%zu\n", GpuFarEligibleTiles.size(),NearGpuTiles,GpuFarCpuFallbackTiles.size()); return true; } void PumpGpuFarGeneration(double MaxPumpBudgetMilliseconds=8.0) { if(!bGpuFarEnabled||!ShapeWorld||!ShapeWorld->hasFarWorld()||!Device||!Context)return; ResolveGpuWarmupLaunchPolicy(false); if(bGpuWarmupDeferredUntilFirstView&&!bGpuWarmupDeferredStarted) { // On an ordinary first-launch cache miss, let the complete CPU // clipmap reach the front buffer before starting cold shader // warmup. Starting after only the first CPU frame competes with // the remaining CPU mesh work and regresses startup. The survival // audit has GPU-owned candidates and needs the first CPU frame to // break its CPU/GPU readiness cycle. const bool bDeferredWarmupGateSatisfied=bGpuFarAuditEnabled ?bCpuReadyFramePresentedBeforeGpu:bWholeViewPresented; if(!bDeferredWarmupGateSatisfied)return; std::string DeferredPipelineError; if(!EnsureGpuFarPipeline(DeferredPipelineError)) { std::fprintf(stderr,"[GpuPipelineInitError] deferred_after_CPU_ready_gate: %s\n", DeferredPipelineError.c_str()); bGpuFarEnabled=false;bGpuWarmupDeferredStarted=true; AddGpuFarCpuFallbackTiles(DesiredTiles); return; } bGpuWarmupDeferredStarted=true; std::printf("[GpuWarmupDeferredStart] at_ms=%.3f gate=%s\n", std::chrono::duration( std::chrono::steady_clock::now()-ColdProcessStart).count(), bGpuFarAuditEnabled?"first_CPU_frame_presented":"whole_CPU_view_presented"); StartGpuShaderWarmupAsync(); } std::string PipelineError; if(!EnsureGpuFarPipeline(PipelineError)) {bGpuFarEnabled=false;AddGpuFarCpuFallbackTiles(DesiredTiles);return;} if(bGpuFarShaderPrewarm&&!bGpuWarmupDeferredUntilFirstView &&!bGpuWarmupCompleted&&!GpuShaderWarmupThread.joinable()) StartGpuShaderWarmupAsync(); StartGpuFarPreparation(); if(!CompleteGpuShaderWarmupAndRoute())return; StartGpuFarPreparation(); if(!bGpuFarEnabled||!FinalizeGpuFarPreparation()||!bGpuFarInputsFinalized ||GpuFarQueue.empty())return; const bool bColdDrainBeforeWholeView=!bInitialClipmapReported&&!bGpuFarAuditEnabled &&!bDisableGpuColdStartDrain&&bGpuFarWarmupBeforeWorkers; constexpr std::size_t StartupFirstGpuBatchTarget=32; constexpr std::size_t StartupGpuBatchTarget=384; constexpr double StartupGpuPumpBudgetMilliseconds=16.0; const bool bWaitForStreamingGpuBatch=!bColdDrainBeforeWholeView &&!bGpuFarAuditEnabled&&!bInitialClipmapReported; const std::size_t GpuPumpTileLimit=bGpuFarAuditEnabled?StartupFirstGpuBatchTarget :(GpuFarSubmissionBatches==0?StartupFirstGpuBatchTarget:StartupGpuBatchTarget); const double GpuPumpBudgetMilliseconds=std::min(MaxPumpBudgetMilliseconds, bWaitForStreamingGpuBatch?StartupGpuPumpBudgetMilliseconds:4.0); if(bWaitForStreamingGpuBatch &&!bGpuFarPreparationFinished.load(std::memory_order_acquire) &&GpuFarQueue.size()(PumpStart-ColdProcessStart).count(); if(GpuFarFirstPumpMs<0.0)GpuFarFirstPumpMs=PumpMs; if(LastGpuFarPumpAt.time_since_epoch().count()!=0) { const double GapMs=std::chrono::duration(PumpStart-LastGpuFarPumpAt).count(); GpuFarPumpGapMs+=GapMs;GpuFarPumpGapMaxMs=std::max(GpuFarPumpGapMaxMs,GapMs); } LastGpuFarPumpAt=PumpStart;GpuFarLastPumpMs=PumpMs;++GpuFarPumpCalls; const bool bDeferredBatch=!bGpuFarAuditEnabled &&!(bAuditGpuSkirtDrawArgs&&bDrawOnlyTile); if(bDeferredBatch) { std::string BatchError; if(!VoxelForgeGpuFarViewer::BeginFarTileBatch(Device,Context,GpuFarShaderPath,BatchError)) { std::fprintf(stderr,"[GpuFarBatchError] begin: %s\n",BatchError.c_str()); bGpuFarEnabled=false;return; } } const auto Start=std::chrono::steady_clock::now(); int32 Built=0; std::vector BuiltKeys; BuiltKeys.reserve(bColdDrainBeforeWholeView?GpuFarQueue.size():GpuPumpTileLimit); do { const FVoxelTileKey Key=GpuFarQueue.front();GpuFarQueue.pop_front();GpuFarQueued.erase(Key); if(!DesiredTileSet.contains(Key)||GpuFarTiles.contains(Key))continue; FGpuFarTile Tile; if(!GpuFarFreeOutputSlots.empty()) {Tile.OutputSlot=GpuFarFreeOutputSlots.back();GpuFarFreeOutputSlots.pop_back();} else if(GpuFarNextOutputSlotsecond; if(!PreparedInput) { const auto PrepError=GpuFarPreparationErrors.find(Key); std::fprintf(stderr,"[GpuFarInputError] key=(%d,%d,%d,lod%d): %s\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level, PrepError==GpuFarPreparationErrors.end()?"prepared far input is missing":PrepError->second.c_str()); GpuFarFreeOutputSlots.push_back(Tile.OutputSlot); bGpuFarEnabled=false; break; } const uint8 PreparedSkirtFaceMask=PreparedInput->visibleSkirtFaceMask; Tile.InputCells=PreparedInput->cells;Tile.InputStep=PreparedInput->step; Tile.bNearDetailInput=PreparedInput->nearDetailEnabled; Tile.ProtectedSamples=PreparedInput->protectedSampleCount; Tile.ProtectedThinSamples=PreparedInput->protectedThinSampleCount; Tile.ProtectedSolidSamples=PreparedInput->protectedSolidSampleCount; Tile.NearProxySamples=static_cast(std::min( PreparedInput->nearPackedProxy.size(),std::numeric_limits::max())); Tile.ConnectorRings=PreparedInput->connectorRingCount; Tile.ConnectorVertices=PreparedInput->connectorVertexCount; Tile.VisibleSkirtFaceMask=PreparedSkirtFaceMask; const auto PanelRangeIt=GpuFarPanelOutputRanges.find(Key); if(PanelRangeIt==GpuFarPanelOutputRanges.end()) { GpuFarFreeOutputSlots.push_back(Tile.OutputSlot); std::fprintf(stderr,"[GpuFarPoolError] panel-output range is missing for key=(%d,%d,%d,lod%d)\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level); GpuFarPanelOutputRanges.erase(Key); bGpuFarEnabled=false; break; } const FGpuFarPanelOutputRange PanelRange=PanelRangeIt->second; if(!VoxelForgeGpuFarViewer::BuildFarTile(Device,Context,*ShapeWorld,CoreKey, PreparedInput, GpuFarShaderPath,&Tile.VertexBuffer,&Tile.IndexBuffer,&Tile.IndirectArgs, &Tile.ConnectorVertexBuffer,&Tile.ConnectorIndexBuffer, Tile.OutputSlot,GpuFarOutputCapacitySlots,&Tile.IndirectArgsByteOffset, bDeferredBatch?nullptr:&Tile.CompletionEvent, &Tile.TimingQueries, ((bGpuFarAuditEnabled&&Key.Level>=6)||bAuditDrawOnlyGpuTile)?&AuditMesh:nullptr, &EnqueueMs,&GpuDispatchMs,Error,true, PanelRange.BaseVertex,PanelRange.CapacityVertices)) { GpuFarFreeOutputSlots.push_back(Tile.OutputSlot); ReleaseGpuFarPanelOutputRange(Key); std::fprintf(stderr,"[GpuFarTileError] key=(%d,%d,%d,lod%d): %s\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level,Error.c_str()); if(PreparedInputIt!=GpuFarPreparedInputs.end())GpuFarPreparedInputs.erase(PreparedInputIt); bGpuFarEnabled=false; break; } if(bAuditDrawOnlyGpuTile) std::printf("[GpuPooledOutputReadback] key=(%d,%d,%d,lod%d) output_slot=%u indirect_offset=%u surface_indices=%u output_vertices=%zu output_indices=%zu sequential_indices=%d indirect_args_valid=%d vertex_stride_bytes=%u status=%s\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level,Tile.OutputSlot, Tile.IndirectArgsByteOffset,AuditMesh.surfaceVertexCount, AuditMesh.vertices.size(),AuditMesh.indices.size(), AuditMesh.sequentialIndices,AuditMesh.indirectArgsValid, static_cast(sizeof(FGpuVertex)), AuditMesh.vertices.size()==AuditMesh.indices.size() &&AuditMesh.sequentialIndices&&AuditMesh.indirectArgsValid?"PASS":"FAIL"); if(bAuditDrawOnlyGpuTile) { std::string CpuTriangleError; const FVector TriangleAuditCameraVoxels(Position.X*4.0,Position.Y*4.0,Position.Z*4.0); const FStandaloneDesiredTileSet TriangleAuditDesired= StandaloneWorldMesher::BuildDesiredSet(*World,TriangleAuditCameraVoxels); int32 CpuBandMin=MIN_int32,CpuBandMax=MAX_int32; if(World->StrateContentCutMinLevel<9&&TriangleAuditDesired.bHasStrate) { CpuBandMin=TriangleAuditDesired.StrateBottomChunkZ*CHUNK_SIZE; CpuBandMax=(TriangleAuditDesired.StrateTopChunkZ+1)*CHUNK_SIZE; } VoxelForgeCore::TileGenerationOptions CpuTriangleOptions; CpuTriangleOptions.bandMinZVoxel=CpuBandMin; CpuTriangleOptions.bandMaxZVoxel=CpuBandMax; auto CpuTriangleMesh=ShapeWorld->generateTile(CoreKey, CpuTriangleOptions,CpuTriangleError); if(!CpuTriangleMesh) { std::printf("[GpuCpuTriangleAudit] key=(%d,%d,%d,lod%d) status=FAIL error=%s\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level,CpuTriangleError.c_str()); } else { using FPoint=std::array; using FTriangle=std::array; std::vector CpuTriangles,GpuTriangles,CpuTriangleNormals, GpuTriangleNormals,CpuSkirtTriangles,GpuSkirtTriangles; std::size_t CpuTriangleCount=0,CpuVisibleSkirtTriangleCount=0; const std::size_t GpuSurfaceVertexCount=std::min( AuditMesh.surfaceVertexCount,AuditMesh.vertices.size()); const std::size_t GpuSkirtStart=std::min( GpuSurfaceVertexCount+AuditMesh.connectorPanelVertexCount, AuditMesh.vertices.size()); const std::size_t GpuSkirtEnd=std::min( GpuSkirtStart+AuditMesh.skirtVertexCount,AuditMesh.vertices.size()); const std::size_t GpuTriangleCount=GpuSurfaceVertexCount/3; CpuTriangles.reserve(CpuTriangleMesh->indices.size()/3); GpuTriangles.reserve(GpuTriangleCount); CpuSkirtTriangles.reserve(CpuTriangleMesh->groups.skirtTriangleCount); GpuSkirtTriangles.reserve((GpuSkirtEnd-GpuSkirtStart)/3); for(std::size_t I=0;I+2indices.size();I+=3) { const std::size_t TriangleIndex=I/3; const uint8 Faces=TriangleIndexskirtFaceMasks.size() ?CpuTriangleMesh->skirtFaceMasks[TriangleIndex]:0; const auto IA=CpuTriangleMesh->indices[I]; const auto IB=CpuTriangleMesh->indices[I+1]; const auto IC=CpuTriangleMesh->indices[I+2]; if(IA>=CpuTriangleMesh->vertices.size()||IB>=CpuTriangleMesh->vertices.size() ||IC>=CpuTriangleMesh->vertices.size())continue; const auto& A=CpuTriangleMesh->vertices[IA].position; const auto& B=CpuTriangleMesh->vertices[IB].position; const auto& C=CpuTriangleMesh->vertices[IC].position; if(Faces==0) { CpuTriangles.push_back({FPoint{A.x,A.y,A.z},FPoint{B.x,B.y,B.z}, FPoint{C.x,C.y,C.z}}); const auto& NA=CpuTriangleMesh->vertices[IA].normal; const auto& NB=CpuTriangleMesh->vertices[IB].normal; const auto& NC=CpuTriangleMesh->vertices[IC].normal; CpuTriangleNormals.push_back({FPoint{NA.x,NA.y,NA.z}, FPoint{NB.x,NB.y,NB.z},FPoint{NC.x,NC.y,NC.z}}); ++CpuTriangleCount; } else if((Faces&PreparedSkirtFaceMask)!=0) { CpuSkirtTriangles.push_back({FPoint{A.x,A.y,A.z},FPoint{B.x,B.y,B.z}, FPoint{C.x,C.y,C.z}}); ++CpuVisibleSkirtTriangleCount; } } for(std::size_t I=0;I+2::infinity(); FPoint CpuSkirtMinimum{Infinity,Infinity,Infinity}; FPoint CpuSkirtMaximum{-Infinity,-Infinity,-Infinity}; FPoint GpuSkirtMinimum{Infinity,Infinity,Infinity}; FPoint GpuSkirtMaximum{-Infinity,-Infinity,-Infinity}; const auto AccumulateBounds=[](const std::vector& Triangles, FPoint& Minimum,FPoint& Maximum) { for(const FTriangle& Triangle:Triangles) for(const FPoint& Point:Triangle) for(int Axis=0;Axis<3;++Axis) { Minimum[Axis]=std::min(Minimum[Axis],Point[Axis]); Maximum[Axis]=std::max(Maximum[Axis],Point[Axis]); } }; AccumulateBounds(CpuSkirtTriangles,CpuSkirtMinimum,CpuSkirtMaximum); AccumulateBounds(GpuSkirtTriangles,GpuSkirtMinimum,GpuSkirtMaximum); constexpr double TriangleVertexToleranceCm=0.05; constexpr double TriangleVertexToleranceSq= TriangleVertexToleranceCm*TriangleVertexToleranceCm; constexpr int TrianglePermutations[6][3]={{0,1,2},{0,2,1},{1,0,2}, {1,2,0},{2,0,1},{2,1,0}}; std::vector MatchedGpuTriangles(GpuTriangles.size(),0); int64 Missing=0,Extra=0; double MaxMatchedVertexErrorCm=0.0; double MaxMatchedSurfaceNormalDelta=0.0,MinMatchedSurfaceNormalDot=1.0; for(std::size_t CpuIndex=0;CpuIndex::infinity(); double BestMaxDistanceSq=0.0; std::size_t BestGpuIndex=GpuTriangles.size(); int BestPermutation[3]={0,1,2}; for(std::size_t GpuIndex=0;GpuIndex1.0e-20&&GpuLengthSq>1.0e-20) MinMatchedSurfaceNormalDot=std::min(MinMatchedSurfaceNormalDot, Dot/std::sqrt(CpuLengthSq*GpuLengthSq)); } } } for(const uint8 Matched:MatchedGpuTriangles)if(!Matched)++Extra; std::vector MatchedGpuSkirts(GpuSkirtTriangles.size(),0); int64 MissingSkirts=0,ExtraSkirts=0; double MaxMatchedSkirtVertexErrorCm=0.0; double MinNearestUnmatchedSkirtErrorCm=Infinity; double MaxNearestUnmatchedSkirtErrorCm=0.0; for(const FTriangle& CpuTriangle:CpuSkirtTriangles) { double BestCost=std::numeric_limits::infinity(); double BestMaxDistanceSq=0.0; double NearestMaxDistanceSq=std::numeric_limits::infinity(); std::size_t BestGpuIndex=GpuSkirtTriangles.size(); for(std::size_t GpuIndex=0;GpuIndexgroups.skirtTriangleCount,PreparedSkirtFaceMask, static_cast(Missing),static_cast(Extra), static_cast(MissingSkirts),static_cast(ExtraSkirts), TriangleVertexToleranceCm,MaxMatchedVertexErrorCm, MaxMatchedSurfaceNormalDelta,MinMatchedSurfaceNormalDot, MaxMatchedSkirtVertexErrorCm, std::isfinite(MinNearestUnmatchedSkirtErrorCm) ?MinNearestUnmatchedSkirtErrorCm:0.0, MaxNearestUnmatchedSkirtErrorCm, CpuSkirtTriangles.empty()?0.0:CpuSkirtMinimum[0], CpuSkirtTriangles.empty()?0.0:CpuSkirtMinimum[1], CpuSkirtTriangles.empty()?0.0:CpuSkirtMinimum[2], CpuSkirtTriangles.empty()?0.0:CpuSkirtMaximum[0], CpuSkirtTriangles.empty()?0.0:CpuSkirtMaximum[1], CpuSkirtTriangles.empty()?0.0:CpuSkirtMaximum[2], GpuSkirtTriangles.empty()?0.0:GpuSkirtMinimum[0], GpuSkirtTriangles.empty()?0.0:GpuSkirtMinimum[1], GpuSkirtTriangles.empty()?0.0:GpuSkirtMinimum[2], GpuSkirtTriangles.empty()?0.0:GpuSkirtMaximum[0], GpuSkirtTriangles.empty()?0.0:GpuSkirtMaximum[1], GpuSkirtTriangles.empty()?0.0:GpuSkirtMaximum[2], Missing==0&&Extra==0&&MissingSkirts==0&&ExtraSkirts==0 &&CpuTriangleCount==GpuTriangleCount &&CpuVisibleSkirtTriangleCount==GpuSkirtTriangles.size()?"PASS":"FAIL"); if(bGpuFarCpuMeshDrawAudit&&bDrawOnlyTile&&IsDrawOnlyTile(Key)) { std::vector CpuDrawVertices;CpuDrawVertices.reserve( CpuTriangleMesh->vertices.size()); for(const auto& Vertex:CpuTriangleMesh->vertices) { FGpuVertex Copy{}; Copy.Position[0]=static_cast(Vertex.position.x*0.01); Copy.Position[1]=static_cast(Vertex.position.y*0.01); Copy.Position[2]=static_cast(Vertex.position.z*0.01); Copy.Normal[0]=static_cast(Vertex.normal.x); Copy.Normal[1]=static_cast(Vertex.normal.y); Copy.Normal[2]=static_cast(Vertex.normal.z); CpuDrawVertices.push_back(Copy); } std::vector CpuDrawIndices;CpuDrawIndices.reserve( CpuTriangleMesh->indices.size()); for(size_t I=0;I+2indices.size();I+=3) { const size_t TriangleIndex=I/3; const uint8 Faces=TriangleIndexskirtFaceMasks.size() ?CpuTriangleMesh->skirtFaceMasks[TriangleIndex]:0; if(Faces!=0&&(Faces&PreparedSkirtFaceMask)==0)continue; CpuDrawIndices.push_back(CpuTriangleMesh->indices[I]); CpuDrawIndices.push_back(CpuTriangleMesh->indices[I+1]); CpuDrawIndices.push_back(CpuTriangleMesh->indices[I+2]); } if(!MakeBuffer(&Tile.ReadbackCopyVertexBuffer,CpuDrawVertices.data(), CpuDrawVertices.size()*sizeof(FGpuVertex),D3D11_BIND_VERTEX_BUFFER) ||!MakeBuffer(&Tile.ReadbackCopyIndexBuffer,CpuDrawIndices.data(), CpuDrawIndices.size()*sizeof(uint32),D3D11_BIND_INDEX_BUFFER)) { std::fprintf(stderr,"[GpuCpuMeshDrawAudit] key=(%d,%d,%d,lod%d) buffer_creation=FAIL\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level); bGpuFarEnabled=false; } else { Tile.ReadbackCopyIndexCount=static_cast(CpuDrawIndices.size()); std::printf("[GpuCpuMeshDrawAudit] key=(%d,%d,%d,lod%d) surface_triangles=%zu all_skirt_triangles=%u visible_skirt_mask=0x%02x draw_indices=%u vertices=%zu path=cpu_mesh_copy\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level,CpuTriangleCount, CpuTriangleMesh->groups.skirtTriangleCount,PreparedSkirtFaceMask, Tile.ReadbackCopyIndexCount,CpuDrawVertices.size()); } } } } if((bGpuFarReadbackCopyDrawAudit||bGpuFarMeterCopyDrawAudit) &&bDrawOnlyTile&&IsDrawOnlyTile(Key) &&!AuditMesh.vertices.empty()&&AuditMesh.vertices.size()==AuditMesh.indices.size()) { std::vector CopyVertices;CopyVertices.reserve(AuditMesh.vertices.size()); for(const auto& Vertex:AuditMesh.vertices) { FGpuVertex Copy{}; for(int Axis=0;Axis<3;++Axis) { Copy.Position[Axis]=Vertex.position[Axis] *(bGpuFarMeterCopyDrawAudit?0.01f:1.0f); Copy.Normal[Axis]=Vertex.normal[Axis]; } CopyVertices.push_back(Copy); } if(!MakeBuffer(&Tile.ReadbackCopyVertexBuffer,CopyVertices.data(), CopyVertices.size()*sizeof(FGpuVertex),D3D11_BIND_VERTEX_BUFFER) ||!MakeBuffer(&Tile.ReadbackCopyIndexBuffer,AuditMesh.indices.data(), AuditMesh.indices.size()*sizeof(uint32),D3D11_BIND_INDEX_BUFFER)) { std::fprintf(stderr,"[GpuReadbackCopyDrawAudit] key=(%d,%d,%d,lod%d) buffer_creation=FAIL\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level); bGpuFarEnabled=false; } else { Tile.ReadbackCopyIndexCount=static_cast(AuditMesh.indices.size()); std::printf("[GpuReadbackCopyDrawAudit] key=(%d,%d,%d,lod%d) indices=%u vertices=%zu coordinates=%s path=unpooled_readback_copy\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level, Tile.ReadbackCopyIndexCount,CopyVertices.size(), bGpuFarMeterCopyDrawAudit?"meters":"centimeters"); } } if(PreparedInputIt!=GpuFarPreparedInputs.end())GpuFarPreparedInputs.erase(PreparedInputIt); if(bGpuFarAuditEnabled&&GpuFarAudit&&Key.Level>=6) { FStandaloneCpuTile AuditTile;AuditTile.Key=Key; AuditTile.SurfaceVertexCount=static_cast(AuditMesh.vertices.size()); AuditTile.Vertices.reserve(AuditMesh.vertices.size()); for(const auto& Vertex:AuditMesh.vertices) AuditTile.Vertices.push_back({ {Vertex.position[0]*0.01f,Vertex.position[1]*0.01f,Vertex.position[2]*0.01f}, {Vertex.normal[0],Vertex.normal[1],Vertex.normal[2]}}); AuditTile.Indices=std::move(AuditMesh.indices); GpuFarAudit->AuditTile(AuditTile); } Tile.VertexCapacityBytes=static_cast( VoxelForgeGpuFarViewer::PooledOutputVertexCapacityPerTile)*32u; const auto PreparedAtIt=GpuFarPreparedAt.find(Key); if(PreparedAtIt!=GpuFarPreparedAt.end())Tile.PreparedAt=PreparedAtIt->second; Tile.SubmittedAt=std::chrono::steady_clock::now(); Tile.GpuDispatchMs=GpuDispatchMs; GpuFarEnqueueWallSeconds+=EnqueueMs/1000.0; if(GpuDispatchMs>0.0) { ReportGpuFarSlowDispatchTile(Key,Tile,GpuDispatchMs); GpuFarGpuDispatchMs+=GpuDispatchMs; if(GpuDispatchMs>GpuFarGpuDispatchMaxMs) { GpuFarGpuDispatchMaxMs=GpuDispatchMs; GpuFarGpuDispatchMaxKey=Key;bGpuFarGpuDispatchMaxKeyValid=true; } Tile.bTimingResolved=true; } ++GpuFarTilesSubmitted; if(Key.LevelFullResClipLevels)++GpuFarNearTilesSubmitted; else ++GpuFarFarTilesSubmitted; ++Built; GpuFarTiles.emplace(Key,Tile); BuiltKeys.push_back(Key); if(!bDeferredBatch&&bGpuFarTimelineEnabled) std::printf("[GpuTileTimeline] event=submitted key=(%d,%d,%d,lod%d) batch=none at_ms=%.3f frame=%llu prepared_ms=%.3f path=direct_dispatch\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level, ColdTimelineMilliseconds(Tile.SubmittedAt), static_cast(ColdTimelineFrame()), ColdTimelineMilliseconds(Tile.PreparedAt)); if(!bGpuFarFirstTileReported) { bGpuFarFirstTileReported=true; std::printf("[GpuFarFirstTile] key=(%d,%d,%d,lod%d) cpu_export_upload_enqueue_ms=%.3f vertex_capacity_mb=%.3f mode=direct-indirect-draw\n", Key.Coord.X,Key.Coord.Y,Key.Coord.Z,Key.Level,EnqueueMs, Tile.VertexCapacityBytes/(1024.0*1024.0)); std::fflush(stdout); } } while(!GpuFarQueue.empty()&&(bColdDrainBeforeWholeView ||(Built( std::chrono::steady_clock::now()-Start).count() 0) { if(bDeferredBatch) { FGpuFarBatch Batch;Batch.TileCount=static_cast(Built); Batch.PreparedAt=std::chrono::steady_clock::now(); Batch.Keys=BuiltKeys; const uint32 BatchIndex=static_cast(GpuFarBatches.size()); if(bGpuFarTimelineEnabled) std::printf("[GpuBatchTimeline] event=prepared batch=%u at_ms=%.3f frame=%llu tile_count=%u path=direct_gpu_output\n", BatchIndex,ColdTimelineMilliseconds(Batch.PreparedAt), static_cast(ColdTimelineFrame()),Batch.TileCount); std::string BatchError; Batch.SubmitStartedAt=std::chrono::steady_clock::now(); if(!VoxelForgeGpuFarViewer::SubmitFarTileBatch(Device,Context,GpuFarShaderPath, &Batch.CompletionEvent,&Batch.TimingQueries,BatchError)) { std::fprintf(stderr,"[GpuFarBatchError] submit: %s\n",BatchError.c_str()); bGpuFarEnabled=false; } else { Batch.SubmittedAt=std::chrono::steady_clock::now(); const double SubmitMs=std::chrono::duration( Batch.SubmittedAt-ColdProcessStart).count(); if(GpuFarFirstSubmitMs<0.0)GpuFarFirstSubmitMs=SubmitMs; GpuFarLastSubmitMs=SubmitMs; GpuFarBatches.push_back(Batch); for(const FVoxelTileKey& Key:BuiltKeys) { auto It=GpuFarTiles.find(Key); if(It!=GpuFarTiles.end()) { It->second.BatchIndex=BatchIndex; It->second.SubmittedAt=Batch.SubmittedAt; 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(ColdTimelineFrame()), ColdTimelineMilliseconds(It->second.PreparedAt)); } } 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( Batch.SubmittedAt-Batch.SubmitStartedAt).count(), static_cast(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(ColdTimelineFrame()),Batch.TileCount, ColdTimelineMilliseconds(Batch.SubmitStartedAt)); ++GpuFarSubmissionBatches; GpuFarMaxTilesPerSubmissionBatch=std::max(GpuFarMaxTilesPerSubmissionBatch, static_cast(Built)); } } else { ++GpuFarSubmissionBatches; GpuFarMaxTilesPerSubmissionBatch=std::max(GpuFarMaxTilesPerSubmissionBatch, static_cast(Built)); } } SampleGpuFarMemory(); const double PumpWallMs=std::chrono::duration( std::chrono::steady_clock::now()-PumpStart).count(); GpuFarPumpWallMs+=PumpWallMs;GpuFarPumpMaxWallMs=std::max(GpuFarPumpMaxWallMs,PumpWallMs); } void ToggleFarRenderer() { if(!bShapeWorld||!ShapeWorld||!ShapeWorld->hasFarWorld()) { bGpuFarEnabled=!bGpuFarEnabled; std::printf("[FarRenderer] GPU far %s; it will take effect when far shapes are ready.\n", bGpuFarEnabled?"enabled":"disabled"); return; } bGpuFarEnabled=!bGpuFarEnabled; if(bGpuFarEnabled) { std::string GpuInitError; if(!EnsureGpuFarPipeline(GpuInitError)) {bGpuFarEnabled=false;return;} bPresentCpuFrameBeforeGpu=true; bHoldCpuFrameDuringGpuWarmup=true; bCpuReadyFramePresentedBeforeGpu=false; ScheduleGpuFarTiles(DesiredTiles); std::vector CpuFar; for(const FVoxelTileKey& Key:DesiredTiles) if(GpuFarEligibleTiles.contains(Key)&&ResidentTiles.contains(Key))CpuFar.push_back(Key); for(const FVoxelTileKey& Key:CpuFar)RemoveResidentTile(Key); } else { GpuFarQueue.clear();GpuFarQueued.clear();GpuFarEligibleTiles.clear(); Streamer->SetDesiredTileFilter(DesiredTiles); } std::vector ResidentKeys;ResidentKeys.reserve(ResidentTiles.size()); for(const auto& Pair:ResidentTiles)ResidentKeys.push_back(Pair.first); const FVector CameraVoxels(Position.X*4.0,Position.Y*4.0,Position.Z*4.0); ++CrossingIndex; const FStandaloneStreamingUpdate Update=Streamer->UpdateDesired( CameraVoxels,ResidentKeys,CrossingIndex); FCrossingWork& Work=CrossingWork[CrossingIndex]; Work.SubmittedJobs=Update.NewJobs;Work.PendingJobs=Update.NewJobs; Work.StartTime=std::chrono::steady_clock::now(); std::printf("[FarRenderer] mode=%s cpu_field_jobs=%d gpu_field_ready=%zu gpu_field_queued=%zu (H toggles)\n", bGpuFarEnabled?"GPU":"CPU",Update.NewJobs,GpuFarTiles.size(),GpuFarQueue.size()); } void TryCompleteShapePipeline() { if(!bShapePipelineActive||InitialNeighborhoodTiles.empty())return; bool bNeighborhoodUploaded=true; for(const FVoxelTileKey& Key:InitialNeighborhoodTiles) if(!ResidentTiles.contains(Key)){bNeighborhoodUploaded=false;break;} bNeighborhoodUploaded &= DirtyBatchSet.empty(); if(bNeighborhoodUploaded&&!bNeighborhoodReadyReported) { bNeighborhoodReadyReported=true; const double Elapsed=std::chrono::duration( std::chrono::steady_clock::now()-ColdProcessStart).count(); std::printf("[NeighborhoodReady] %.3fs after cold process start; tiles=%zu/%zu vertices=%llu indices=%llu\n", Elapsed,InitialNeighborhoodTiles.size(),InitialNeighborhoodTiles.size(), static_cast(TotalVertices), static_cast(TotalIndices)); std::fflush(stdout); } if(!bNeighborhoodReadyReported ||!bFullShapeBuildFinished.load(std::memory_order_acquire))return; if(FullShapeBuildThread.joinable())FullShapeBuildThread.join(); if(!bFullShapeBuildSucceeded||!PendingFullShapeWorld) { bShapePipelineActive=false;bGenerationRunning=false; std::fprintf(stderr,"[ShapePipeline] full shape build failed: %s\n", FullShapeBuildError.c_str()); PostMessageA(Window,WM_CLOSE,0,0); return; } const double FullShapeSeconds=std::chrono::duration( std::chrono::steady_clock::now()-FullShapeBuildStart).count(); if(Streamer)Streamer->Stop(); Streamer.reset(); ShapeWorld=std::move(PendingFullShapeWorld); bFarShapeStagePending=false;bShapePipelineActive=false; const FVector CameraVoxels(Position.X*4.0,Position.Y*4.0,Position.Z*4.0); Streamer=std::make_unique(*World,WorkerCount,false,nullptr,-1, false,false,false,false,ShapeWorld.get()); if(bGpuFarEnabled&&ShapeWorld->hasFarWorld()) { ScheduleGpuFarTiles(DesiredTiles); if(bGpuFarAuditEnabled) { std::vector AuditKeys;AuditKeys.reserve(GpuFarEligibleTiles.size()); for(const FVoxelTileKey& Key:DesiredTiles) if(Key.Level>=6&&GpuFarEligibleTiles.contains(Key))AuditKeys.push_back(Key); GpuFarAudit=std::make_unique(*World,*ShapeWorld,AuditKeys,false); } std::vector CpuResidentNear; for(const auto& Pair:ResidentTiles) if(Pair.first.LevelFullResClipLevels &&GpuFarEligibleTiles.contains(Pair.first))CpuResidentNear.push_back(Pair.first); for(const FVoxelTileKey& Key:CpuResidentNear)RemoveResidentTile(Key); } std::vector ResidentKeys;ResidentKeys.reserve(ResidentTiles.size()); for(const auto& Pair:ResidentTiles)ResidentKeys.push_back(Pair.first); ++CrossingIndex; const FStandaloneStreamingUpdate Update=Streamer->Start(CameraVoxels,ResidentKeys,CrossingIndex); if(Update.DesiredTiles!=static_cast(DesiredTiles.size())) { Streamer->Stop();Streamer.reset();bGenerationRunning=false; std::fprintf(stderr,"[ShapePipeline] full streamer accepted %d of %zu desired tiles.\n", Update.DesiredTiles,DesiredTiles.size()); PostMessageA(Window,WM_CLOSE,0,0); return; } FCrossingWork& Work=CrossingWork[CrossingIndex]; Work.SubmittedJobs=Update.NewJobs;Work.PendingJobs=Update.NewJobs; Work.StartTime=std::chrono::steady_clock::now(); bGenerationRunning=true; std::printf("[ShapePipelineFullReady] full_shape=%.3fs retained=%d new_jobs=%d workers=%d; filling outward\n", FullShapeSeconds,Update.RetainedResidentTiles,Update.NewJobs,WorkerCount); std::fflush(stdout); } void MarkBatchDirty(const FStandaloneBatchKey& Key) {DirtyBatchSet.insert(Key);} void RefreshResidentSkirtMasks() { for(auto& [Key,Resident]:ResidentTiles) { if(!DesiredTileSet.contains(Key))continue; const uint8 NewMask=ComputeVisibleSkirtFaceMask(Key,DesiredTileSet); if(NewMask==Resident.ActiveSkirtFaceMask)continue; Resident.ActiveSkirtFaceMask=NewMask; MarkBatchDirty(BatchForTile(Key)); } } static bool TileKeyLess(const FVoxelTileKey& A,const FVoxelTileKey& B) { if(A.Level!=B.Level)return A.Levelsecond; Items.erase(std::remove(Items.begin(),Items.end(),Key),Items.end()); if(Items.empty())BatchMembers.erase(Members); } MarkBatchDirty(Batch); ResidentTiles.erase(Resident); } void RecenterStreaming() { if(!World||!Streamer)return; const FVector CameraVoxels(Position.X*4.0,Position.Y*4.0,Position.Z*4.0); FStandaloneDesiredTileSet NewDesired=StandaloneWorldMesher::BuildDesiredSet(*World,CameraVoxels); if(bShapeWorld&&ShapeWorld) { const auto CoreTiles=ShapeWorld->desiredTiles( {CameraVoxels.X,CameraVoxels.Y,CameraVoxels.Z}); NewDesired.Tiles.clear();NewDesired.Tiles.reserve(CoreTiles.size()); for(const auto& Key:CoreTiles) NewDesired.Tiles.emplace_back( FIntVector(Key.coordinate.x,Key.coordinate.y,Key.coordinate.z),Key.lod); } if(NewDesired.CenterChunk==BuildTargetChunk)return; const FIntVector Previous=BuildTargetChunk; const FIntVector CenterDelta(NewDesired.CenterChunk.X-Previous.X, NewDesired.CenterChunk.Y-Previous.Y,NewDesired.CenterChunk.Z-Previous.Z); if(FlightTargetCrossings>0&&bFlightStarted&&!bFlightFinished) { ++FlightObservedCrossings; if(CenterDelta.X!=0||CenterDelta.Y!=1||CenterDelta.Z!=0) bFlightCrossingsValid=false; } std::unordered_set NewSet; NewSet.reserve(NewDesired.Tiles.size()*2+1); for(const FVoxelTileKey& Key:NewDesired.Tiles)NewSet.insert(Key); std::vector Leavers; for(const auto& Pair:ResidentTiles)if(!NewSet.contains(Pair.first))Leavers.push_back(Pair.first); const auto CrossingStart=std::chrono::steady_clock::now(); double PageCompileSeconds=0.0; uint64 PageCoveredTiles=0; VoxelForgeCore::TileRegionCompileStats PageStats; const uint64 NextCrossing=CrossingIndex+1; FCrossingWork& NextWork=CrossingWork[NextCrossing]; NextWork.StartTime=CrossingStart; for(const FVoxelTileKey& Key:NewDesired.Tiles) if(NewSet.contains(Key)&&!ResidentTiles.contains(Key)) { NextWork.NearestNewTile=Key; NextWork.bHasNearestNewTile=true; break; } if(bShapeWorld&&ShapeWorld) { std::vector NewCoreTiles; NewCoreTiles.reserve(NewDesired.Tiles.size()); for(const FVoxelTileKey& Key:NewDesired.Tiles) if(!ResidentTiles.contains(Key)) NewCoreTiles.push_back({{Key.Coord.X,Key.Coord.Y,Key.Coord.Z},Key.Level}); std::string PageError; size_t CompiledPageCount=0; if(!ShapeWorld->compileTileRegion(NewCoreTiles, static_cast(std::clamp(WorkerCount,1,16)),CoreScheduler,PageError, &CompiledPageCount,&PageStats,true)) { std::fprintf(stderr,"[ShapeRegionPage] compile failed at center=(%d,%d,%d): %s\n", NewDesired.CenterChunk.X,NewDesired.CenterChunk.Y,NewDesired.CenterChunk.Z, PageError.c_str()); return; } PageCoveredTiles=static_cast(CompiledPageCount); std::vector CoreDesired; CoreDesired.reserve(NewDesired.Tiles.size()); for(const FVoxelTileKey& Key:NewDesired.Tiles) CoreDesired.push_back({{Key.Coord.X,Key.Coord.Y,Key.Coord.Z},Key.Level}); ShapeWorld->retainTileRegions(CoreDesired); for(const FVoxelTileKey& Key:Leavers)DeferredLeaverTiles.insert(Key); const double PageSeconds=std::chrono::duration( std::chrono::steady_clock::now()-CrossingStart).count(); PageCompileSeconds=PageStats.wallSeconds; std::printf("[ShapeRegionPage] region_mode=analytic-lod-slab center=(%d,%d,%d) requested_tiles=%zu page_covered_tiles=%llu regions=%zu lattice_nodes=%llu worker_limit=%d shape=%.4fs intervals_signs=%.4fs detail=%.4fs core_worker_sum=%.4fs seconds=%.4f retained_resident=%zu deferred_leavers=%zu\n", NewDesired.CenterChunk.X,NewDesired.CenterChunk.Y,NewDesired.CenterChunk.Z, NewCoreTiles.size(),static_cast(PageCoveredTiles), PageStats.regionsBuilt,static_cast(PageStats.latticeNodes), std::clamp(WorkerCount,1,16),PageStats.shapeSeconds,PageStats.intervalSeconds, PageStats.surfaceSeconds,PageStats.workerSeconds,PageSeconds, ResidentTiles.size()-std::min(ResidentTiles.size(),Leavers.size()),Leavers.size()); } else { for(const FVoxelTileKey& Key:Leavers)RemoveResidentTile(Key); } DesiredTiles=NewDesired.Tiles; DesiredTileSet=std::move(NewSet); for(auto It=GpuFarTiles.begin();It!=GpuFarTiles.end();) { if(DesiredTileSet.contains(It->first)){++It;continue;} GpuFarFreeOutputSlots.push_back(It->second.OutputSlot); ReleaseGpuFarTile(It->second); It=GpuFarTiles.erase(It); } ScheduleGpuFarTiles(DesiredTiles); RefreshResidentSkirtMasks(); for(int32 I=0;I<=MaxLevels;++I)DesiredByLevel[I]=0; for(const FVoxelTileKey& Tile:DesiredTiles)++DesiredByLevel[Tile.Level]; std::vector ResidentKeys;ResidentKeys.reserve(ResidentTiles.size()); for(const auto& Pair:ResidentTiles) if(DesiredTileSet.contains(Pair.first))ResidentKeys.push_back(Pair.first); ++CrossingIndex; const FStandaloneStreamingUpdate Update=Streamer->UpdateDesiredWithSet( std::move(NewDesired),ResidentKeys,CrossingIndex); for(const auto& Pair:Update.CancelledByCrossing) { FCrossingWork& Work=CrossingWork[Pair.first]; Work.PendingJobs=Work.PendingJobs>=Pair.second?Work.PendingJobs-Pair.second:0; Work.CancelledQueuedJobs+=Pair.second; } FCrossingWork& Work=CrossingWork[CrossingIndex]; Work.SubmittedJobs=Update.NewJobs;Work.PendingJobs=Update.NewJobs; Work.PageCoveredTiles=PageCoveredTiles;Work.CorePageSeconds=PageCompileSeconds; Work.CorePageWorkerSeconds=PageStats.workerSeconds; Work.PageRegions=PageStats.regionsBuilt;Work.PageLatticeNodes=PageStats.latticeNodes; BuildTargetChunk=Update.CenterChunk;bGenerationRunning=true; std::printf("[ChunkCrossing] id=%llu center=(%d,%d,%d) delta=(%d,%d,%d) desired=%d retained=%d new_jobs=%d deferred_resident=%zu cancelled_queued=%d full_detail=%d\n", static_cast(CrossingIndex),Update.CenterChunk.X,Update.CenterChunk.Y,Update.CenterChunk.Z, Update.CenterChunk.X-Previous.X,Update.CenterChunk.Y-Previous.Y,Update.CenterChunk.Z-Previous.Z, Update.DesiredTiles,Update.RetainedResidentTiles,Update.NewJobs, bShapeWorld?Leavers.size():0, Update.CancelledQueuedJobs,Update.FullResTiles); std::fflush(stdout); ReportCrossingWork(); } bool RebuildBatch(const FStandaloneBatchKey& Key) { auto MembersIt=BatchMembers.find(Key); auto Existing=StreamingBatches.find(Key); if(MembersIt==BatchMembers.end()||MembersIt->second.empty()) { if(Existing!=StreamingBatches.end()) { TotalVertices-=Existing->second.VertexCount;TotalIndices-=Existing->second.IndexCount; if(Existing->second.VertexBuffer)Existing->second.VertexBuffer->Release(); if(Existing->second.IndexBuffer)Existing->second.IndexBuffer->Release(); StreamingBatches.erase(Existing); } return true; } std::vector Members=MembersIt->second; std::sort(Members.begin(),Members.end(),TileKeyLess); size_t VertexCount=0,IndexCount=0; for(const FVoxelTileKey& Tile:Members) { const auto It=ResidentTiles.find(Tile);if(It==ResidentTiles.end())continue; const FResidentTileMesh& Resident=It->second; VertexCount+=Resident.Vertices.size(); if(Resident.TriangleSkirtFaceMasks.size()==Resident.Indices.size()/3) { for(const uint8 Faces:Resident.TriangleSkirtFaceMasks) if(Faces==0||(Faces&Resident.ActiveSkirtFaceMask)!=0)IndexCount+=3; } else IndexCount+=Resident.Indices.size(); } if(VertexCount==0||IndexCount==0) { if(Existing!=StreamingBatches.end()) { TotalVertices-=Existing->second.VertexCount;TotalIndices-=Existing->second.IndexCount; if(Existing->second.VertexBuffer)Existing->second.VertexBuffer->Release(); if(Existing->second.IndexBuffer)Existing->second.IndexBuffer->Release(); StreamingBatches.erase(Existing); } return true; } if(VertexCount>std::numeric_limits::max()||IndexCount>std::numeric_limits::max()) {std::fprintf(stderr,"LOD %d batch exceeded D3D11 limits.\n",Key.Level);return false;} std::vector Vertices;Vertices.reserve(VertexCount); std::vector 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(Vertices.size()); const FResidentTileMesh& Resident=It->second; for(const FStandaloneCpuVertex& V:Resident.Vertices) Vertices.push_back({{V.Position[0],V.Position[1],V.Position[2]},{V.Normal[0],V.Normal[1],V.Normal[2]}}); const bool bHasFaceMasks=Resident.TriangleSkirtFaceMasks.size()==Resident.Indices.size()/3; for(size_t Triangle=0;Triangle(Resident.ActiveSkirtFaceMask), static_cast(SurfaceTriangles), static_cast(AllSkirtTriangles), static_cast(VisibleSkirtTriangles), static_cast(Indices.size()-TileIndexStart)); bDrawOnlyCpuTriangleAuditReported=true; } if(bDrawOnlyTile&&IsDrawOnlyTile(Tile)) { DrawOnlyIndexStart=static_cast(TileIndexStart); DrawOnlyIndexCount=static_cast(Indices.size()-TileIndexStart); } } FStreamingGpuBatch NewBatch; const bool bVertex=MakeBuffer(&NewBatch.VertexBuffer,Vertices.data(),Vertices.size()*sizeof(FGpuVertex),D3D11_BIND_VERTEX_BUFFER); const bool bIndex=bVertex&&MakeBuffer(&NewBatch.IndexBuffer,Indices.data(),Indices.size()*sizeof(uint32),D3D11_BIND_INDEX_BUFFER); if(!bIndex) { if(NewBatch.VertexBuffer)NewBatch.VertexBuffer->Release(); std::fprintf(stderr,"D3D11 upload failed for LOD %d batch (%d,%d,%d).\n",Key.Level,Key.X,Key.Y,Key.Z); return false; } NewBatch.IndexCount=static_cast(Indices.size());NewBatch.VertexCount=Vertices.size(); NewBatch.DrawOnlyIndexStart=DrawOnlyIndexStart; NewBatch.DrawOnlyIndexCount=DrawOnlyIndexCount; if(Existing!=StreamingBatches.end()) { TotalVertices-=Existing->second.VertexCount;TotalIndices-=Existing->second.IndexCount; if(Existing->second.VertexBuffer)Existing->second.VertexBuffer->Release(); if(Existing->second.IndexBuffer)Existing->second.IndexBuffer->Release(); Existing->second=NewBatch; } else StreamingBatches.emplace(Key,NewBatch); TotalVertices+=NewBatch.VertexCount;TotalIndices+=NewBatch.IndexCount; return true; } void UploadDirtyBatches() { if(DirtyBatchSet.empty())return; std::vector Dirty(DirtyBatchSet.begin(),DirtyBatchSet.end()); const FIntVector Center=Streamer?Streamer->CenterChunk():BuildTargetChunk; auto Distance=[&](const FStandaloneBatchKey& K) { const double Scale=static_cast(1<=MaxBatchUploadsPerFrame)break; if(!bDrainColdStart&&Uploaded>0&&BatchUploadBudgetMilliseconds>0.0 &&std::chrono::duration(std::chrono::steady_clock::now()-Start).count()>=BatchUploadBudgetMilliseconds)break; if(!DirtyBatchSet.contains(Key))continue; if(RebuildBatch(Key)) { DirtyBatchSet.erase(Key);++Uploaded; if(bGpuFarTimelineEnabled) { const auto UploadAt=std::chrono::steady_clock::now(); const bool bHasUploadBuffer=StreamingBatches.contains(Key); std::printf("[CpuUploadBatchTimeline] event=uploaded batch=(lod%d,%d,%d,%d) at_ms=%.3f frame=%llu has_buffer=%s\n", Key.Level,Key.X,Key.Y,Key.Z,ColdTimelineMilliseconds(UploadAt), static_cast(ColdTimelineFrame()), bHasUploadBuffer?"yes":"no_empty_mesh"); const auto MembersIt=BatchMembers.find(Key); if(MembersIt!=BatchMembers.end())for(const FVoxelTileKey& TileKey:MembersIt->second) { auto ResidentIt=ResidentTiles.find(TileKey); if(ResidentIt==ResidentTiles.end()||ResidentIt->second.bColdTimelineResidentReported)continue; FResidentTileMesh& Resident=ResidentIt->second; Resident.bColdTimelineResidentReported=true; std::printf("[CpuTileTimeline] event=uploaded key=(%d,%d,%d,lod%d) at_ms=%.3f frame=%llu batch=(lod%d,%d,%d,%d) queued_ms=%.3f started_ms=%.3f finished_ms=%.3f method=%s\n", TileKey.Coord.X,TileKey.Coord.Y,TileKey.Coord.Z,TileKey.Level, ColdTimelineMilliseconds(UploadAt),static_cast(ColdTimelineFrame()), Key.Level,Key.X,Key.Y,Key.Z,ColdTimelineMilliseconds(Resident.CpuQueuedAt), ColdTimelineMilliseconds(Resident.CpuStartedAt),ColdTimelineMilliseconds(Resident.CpuFinishedAt), bHasUploadBuffer?"cpu_batch_vertex_index":"empty_surface_no_gpu_copy"); std::printf("[CpuTileTimeline] event=resident key=(%d,%d,%d,lod%d) at_ms=%.3f frame=%llu batch=(lod%d,%d,%d,%d)\n", TileKey.Coord.X,TileKey.Coord.Y,TileKey.Coord.Z,TileKey.Level, ColdTimelineMilliseconds(UploadAt),static_cast(ColdTimelineFrame()), Key.Level,Key.X,Key.Y,Key.Z); } } } } } bool IsFullDetailUploaded() { if(!Streamer||World->FullResClipLevels<=0)return false; int32 DesiredFullRes=0,ReadyFullRes=0; for(const FVoxelTileKey& Key:DesiredTiles) { if(Key.Level>=World->FullResClipLevels)continue; ++DesiredFullRes; if(IsRenderedTileReady(Key))++ReadyFullRes; } if(ReadyFullRes!=DesiredFullRes)return false; for(const FStandaloneBatchKey& Key:DirtyBatchSet)if(Key.LevelFullResClipLevels)return false; return true; } void ReportTileTimings() { for(int32 L=0;L<=World->MaxClipLevel;++L) { if(GeneratedByLevel[L](DesiredByLevel[L])||DesiredByLevel[L]==0)continue; std::vector& Times=TileSecondsByLevel[L];if(Times.empty())continue; std::sort(Times.begin(),Times.end()); const double Average=WorkerSecondsByLevel[L]/static_cast(GeneratedByLevel[L]); const double P50=Times[(Times.size()-1)*50/100]; const double P95=Times[(Times.size()-1)*95/100]; std::printf("[TileTiming] LOD=%d generated=%llu target=%d samples=%.2fM worker_sum=%.3fs avg=%.3fms p50=%.3fms p95=%.3fms\n", L,static_cast(GeneratedByLevel[L]),DesiredByLevel[L], static_cast(SamplesByLevel[L])/1.0e6,WorkerSecondsByLevel[L],Average*1000.0,P50*1000.0,P95*1000.0); if(bProfileAttribution) { std::printf("[TileProfile] LOD=%d",L); for(size_t I=0;I(ProfileCyclesByLevel[L][I]) *FPlatformTime::GetSecondsPerCycle64()*1000.0; if(Ms>0.001)std::printf(" %s=%.3fms", VoxelDensityProfile::BucketName(static_cast(I)),Ms); } std::printf("\n"); } Times.clear(); } } void ReportCrossingWork() { for(auto& Pair:CrossingWork) { FCrossingWork& Work=Pair.second; if(Work.bReported||Work.PendingJobs!=0)continue; Work.bReported=true; const double AverageMs=Work.FinishedJobs>0 ?Work.WorkerSeconds*1000.0/static_cast(Work.FinishedJobs):0.0; Work.WallSeconds=Work.StartTime.time_since_epoch().count()!=0 ?std::chrono::duration(std::chrono::steady_clock::now()-Work.StartTime).count():0.0; const double NearestReadyMs=Work.NearestReadySeconds>=0.0 ?Work.NearestReadySeconds*1000.0:-1.0; std::printf("[ChunkCrossingWork] id=%llu submitted=%llu finished=%llu generated=%llu cancelled_queued=%llu stale=%llu samples=%.2fM page_covered_tiles=%llu page_regions=%llu page_nodes=%llu core_page=%.4fs core_page_worker=%.4fs nearest_ready=%.3fms nearest_tile=(%d,%d,%d,lod%d) worker_sum=%.3fs wall=%.3fs avg=%.3fms\n", static_cast(Pair.first), static_cast(Work.SubmittedJobs), static_cast(Work.FinishedJobs), static_cast(Work.Tiles), static_cast(Work.CancelledQueuedJobs), static_cast(Work.StaleResults), static_cast(Work.Samples)/1.0e6, static_cast(Work.PageCoveredTiles), static_cast(Work.PageRegions), static_cast(Work.PageLatticeNodes), Work.CorePageSeconds,Work.CorePageWorkerSeconds,NearestReadyMs, Work.NearestNewTile.Coord.X,Work.NearestNewTile.Coord.Y, Work.NearestNewTile.Coord.Z,Work.NearestNewTile.Level, Work.WorkerSeconds,Work.WallSeconds,AverageMs); for(int32 Level=0;Level<=MaxLevels;++Level) if(Work.TilesByLevel[Level]>0) std::printf("[ChunkCrossingLevel] id=%llu lod=%d tiles=%llu samples=%.3fM worker_sum=%.4fs avg=%.3fms\n", static_cast(Pair.first),Level, static_cast(Work.TilesByLevel[Level]), static_cast(Work.SamplesByLevel[Level])/1.0e6, Work.WorkerSecondsByLevel[Level], Work.WorkerSecondsByLevel[Level]*1000.0/ static_cast(Work.TilesByLevel[Level])); } } void PumpGeneration() { if(bRebuildPending){StartGeneration();return;} if(!Streamer)return; std::vector Ready=Streamer->TakeReady(); for(FStandaloneCpuTile& Tile:Ready) { const int32 Level=Tile.Key.Level; FCrossingWork& Crossing=CrossingWork[Tile.RequestedCrossing]; if(Crossing.PendingJobs>0)--Crossing.PendingJobs; ++Crossing.FinishedJobs;Crossing.Samples+=Tile.DensitySamples;Crossing.WorkerSeconds+=Tile.WorkerSeconds; if(Level>=0&&Level<=MaxLevels) { ++Crossing.TilesByLevel[Level]; Crossing.SamplesByLevel[Level]+=Tile.DensitySamples; Crossing.WorkerSecondsByLevel[Level]+=Tile.WorkerSeconds; } if(Crossing.bHasNearestNewTile&&Tile.Key==Crossing.NearestNewTile &&Crossing.NearestReadySeconds<0.0) Crossing.NearestReadySeconds=std::chrono::duration( Tile.CompletedAt-Crossing.StartTime).count(); if(!Streamer->IsDesired(Tile.Key)||ResidentTiles.contains(Tile.Key)) {++Crossing.StaleResults;continue;} ++Crossing.Tiles; ++GeneratedByLevel[Level];SamplesByLevel[Level]+=Tile.DensitySamples;WorkerSecondsByLevel[Level]+=Tile.WorkerSeconds; if(bProfileAttribution)for(size_t I=0;I ReadyToDrop; for(const FVoxelTileKey& Key:DeferredLeaverTiles) { if(Streamer->IsDesired(Key))continue; if(ResidentTiles.contains(Key))ReadyToDrop.push_back(Key); } for(const FVoxelTileKey& Key:ReadyToDrop)RemoveResidentTile(Key); DeferredLeaverTiles.clear(); } } if(bShapePipelineActive)TryCompleteShapePipeline(); if(FlightTargetCrossings>0&&bFlightFinished&&!bFlightClosePosted &&DirtyBatchSet.empty()&&DeferredLeaverTiles.empty()) { bool bAllFlightWorkReported=true; bool bCrossingLatencyUnderTarget=true; double MaxCrossingWallSeconds=0.0,MaxWorkerCpuSeconds=0.0; std::vector NearestReadyMilliseconds; for(uint64 Crossing=FlightStartCrossingIndex+1; Crossing<=CrossingIndex;++Crossing) { const auto It=CrossingWork.find(Crossing); if(It==CrossingWork.end()||!It->second.bReported) {bAllFlightWorkReported=false;continue;} const FCrossingWork& Work=It->second; MaxCrossingWallSeconds=std::max(MaxCrossingWallSeconds,Work.WallSeconds); MaxWorkerCpuSeconds=std::max(MaxWorkerCpuSeconds,Work.WorkerSeconds); if(Work.WallSeconds>=0.200)bCrossingLatencyUnderTarget=false; if(Work.NearestReadySeconds>=0.0) NearestReadyMilliseconds.push_back(Work.NearestReadySeconds*1000.0); } if(bAllFlightWorkReported) { bFlightClosePosted=true; const double Elapsed=std::chrono::duration( std::chrono::steady_clock::now()-FlightStartTime).count(); const uint64 CacheHits=Streamer?Streamer->GetCacheHits():0; std::size_t DesiredResidentCount=0; for(const FVoxelTileKey& Key:DesiredTiles) if(IsRenderedTileReady(Key))++DesiredResidentCount; std::sort(NearestReadyMilliseconds.begin(),NearestReadyMilliseconds.end()); const auto Percentile=[&](std::size_t Percent) { if(NearestReadyMilliseconds.empty())return -1.0; const std::size_t Index=(NearestReadyMilliseconds.size()-1)*Percent/100; return NearestReadyMilliseconds[Index]; }; const double NearestMaximum=NearestReadyMilliseconds.empty()?-1.0: NearestReadyMilliseconds.back(); const std::size_t MissingDesired=DesiredTiles.size()-DesiredResidentCount; const bool bPass=FlightObservedCrossings==FlightTargetCrossings &&bFlightCrossingsValid&&CacheHits==0&&bCrossingLatencyUnderTarget &&MissingDesired==0&&DeferredLeaverTiles.empty()&&DirtyBatchSet.empty(); std::printf("[FlightBenchmarkComplete] crossings=%d/%d speed=%.2fm/s elapsed=%.3fs cache_hits=%llu crossing_deltas=%s nearest_ready_p50=%.3fms nearest_ready_p95=%.3fms nearest_ready_max=%.3fms max_crossing_wall=%.3fs max_worker_cpu_sum=%.3fs resident=%zu/%zu missing_tiles=%zu deferred_leavers=%zu uploads_drained=%s status=%s\n", FlightObservedCrossings,FlightTargetCrossings,FlightSpeedMps,Elapsed, static_cast(CacheHits), bFlightCrossingsValid?"unit-+Y":"invalid", Percentile(50),Percentile(95),NearestMaximum,MaxCrossingWallSeconds, MaxWorkerCpuSeconds,DesiredResidentCount,DesiredTiles.size(),MissingDesired, DeferredLeaverTiles.size(),DirtyBatchSet.empty()?"yes":"no", bPass?"PASS":"FAIL"); std::fflush(stdout); PostMessageA(Window,WM_CLOSE,0,0); } } if(!bShapePipelineActive&&!bFullDetailReported&&IsFullDetailUploaded()) { bFullDetailReported=true; const double Elapsed=std::chrono::duration(std::chrono::steady_clock::now()-ColdProcessStart).count(); const std::size_t DesiredNear=static_cast(std::count_if( DesiredTiles.begin(),DesiredTiles.end(),[&](const FVoxelTileKey& Key) {return Key.LevelFullResClipLevels;})); std::printf("[FullDetailReady] %.3f s after cold process start; rendered=%zu/%zu tiles through LOD%d.\n", Elapsed,DesiredNear,DesiredNear,World->FullResClipLevels-1); std::printf("[ColdTimeline] event=near_all_tiles_ready at_ms=%.3f waits_for=all_%zu_LOD0_1_gpu_or_cpu_tiles\n", Elapsed*1000.0,DesiredNear); ReportTileTimings();std::fflush(stdout); StartFarShapeGeneration(); } size_t DesiredResidentCount=0; for(const FVoxelTileKey& Key:DesiredTiles) if(IsRenderedTileReady(Key))++DesiredResidentCount; if(!bInitialClipmapReported&&DesiredResidentCount==DesiredTiles.size()&&DirtyBatchSet.empty()) { bInitialClipmapReported=true; const double Elapsed=std::chrono::duration(std::chrono::steady_clock::now()-ColdProcessStart).count(); std::printf("[InitialClipmapReady] %.3f s after cold process start; %zu tiles, %llu vertices, %llu indices, %zu GPU batches.\n", Elapsed,DesiredResidentCount,static_cast(TotalVertices), static_cast(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()); if(GpuShaderWarmupThread.joinable() &&!bGpuShaderWarmupQueueFinished.load(std::memory_order_acquire)) { const bool bPriorityBoosted=SetThreadPriority( GpuShaderWarmupThread.native_handle(),THREAD_PRIORITY_HIGHEST)!=0; std::printf("[GpuShaderWarmupPriorityBoost] at_ms=%.3f reason=CPU_initial_clipmap_ready result=%s\n", Elapsed*1000.0,bPriorityBoosted?"highest":"failed"); } 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(StartupNonBlockingPresentCalls), static_cast(StartupNonBlockingPresentSkips), static_cast(GpuWarmupHeldPresents)); if(bGpuFarEnabled) { SampleGpuFarMemory(); double CpuMeshWorkerSeconds=0.0; uint64 CpuMeshTiles=0,CpuNearMeshTiles=0,CpuFarMeshTiles=0; for(int32 Level=0;Level<=MaxLevels;++Level) { CpuMeshWorkerSeconds+=WorkerSecondsByLevel[Level]; CpuMeshTiles+=GeneratedByLevel[Level]; if(LevelFullResClipLevels)CpuNearMeshTiles+=GeneratedByLevel[Level]; else CpuFarMeshTiles+=GeneratedByLevel[Level]; } const double AverageGpuMs=GpuFarTilesSubmitted ?GpuFarGpuDispatchMs/static_cast(GpuFarTilesSubmitted):0.0; if(bGpuFarGpuDispatchMaxKeyValid) std::printf("[GpuFarMaxDispatchTile] key=(%d,%d,%d,lod%d) dispatch_ms=%.6f\n", GpuFarGpuDispatchMaxKey.Coord.X,GpuFarGpuDispatchMaxKey.Coord.Y, GpuFarGpuDispatchMaxKey.Coord.Z,GpuFarGpuDispatchMaxKey.Level, GpuFarGpuDispatchMaxMs); std::printf("[GpuFarModeTiming] mode=%s cpu_mesh_tiles=%llu cpu_mesh_worker_sum_s=%.6f cpu_input_export_worker_sum_s=%.6f gpu_submitted_tiles=%llu gpu_busy_timestamp_sum_ms=%.3f whole_view_wall_s=%.6f warmup_cpu_claimed=%llu warmup_gpu_takeover=%llu\n", bGpuFarAuditEnabled?"gpu_audit":"gpu_hybrid", static_cast(CpuMeshTiles),CpuMeshWorkerSeconds, GpuFarPreparationWorkerMs/1000.0, static_cast(GpuFarTilesSubmitted),GpuFarGpuDispatchMs, Elapsed,static_cast(GpuFarWarmupCpuClaimedTiles), static_cast(GpuFarWarmupGpuTakeoverTiles)); std::printf("[GpuFarFieldConsumerSummary] gpu_near_tiles_submitted=%llu gpu_far_tiles_submitted=%llu gpu_near_inputs_prepared=%llu gpu_far_inputs_prepared=%llu cpu_near_mesh_tiles=%llu cpu_far_mesh_tiles=%llu near_gpu_lattice_samples=%llu near_packed_candidate_samples=%llu near_proxy_samples_omitted_for_gpu=%llu protected_route_samples=%llu protected_thin_sign_samples=%llu protected_solid_samples=%llu protected_stratum_seal_samples=%llu protected_solid_overlay_samples=%llu collision_source=cpu_reference hashes_source=cpu_reference\n", static_cast(GpuFarNearTilesSubmitted), static_cast(GpuFarFarTilesSubmitted), static_cast(GpuFarPreparedNearTileInputs), static_cast(GpuFarPreparedFarTileInputs), static_cast(CpuNearMeshTiles), static_cast(CpuFarMeshTiles), static_cast(GpuFarNearLatticeSamples), static_cast(GpuFarNearPackedCandidateSamples), static_cast(GpuFarNearPackedSkippedSamples), static_cast(GpuFarProtectedRouteSamples), static_cast(GpuFarProtectedThinSamples), static_cast(GpuFarProtectedSolidSamples), static_cast(GpuFarProtectedSealSamples), static_cast(GpuFarProtectedOverlaySamples)); std::printf("[GpuFarTiming] submitted_tiles=%llu submission_batches=%llu max_tiles_per_batch=%u pooled_output_reserve_wall_ms=%.3f cpu_input_prepare_wall_ms=%.3f cpu_input_worker_sum_ms=%.3f cpu_upload_enqueue_sum_ms=%.3f gpu_dispatch_timestamp_total_ms=%.3f gpu_dispatch_mean_per_tile_ms=%.6f gpu_dispatch_max_tile_ms=%.6f gpu_submission_span_total_ms=%.3f gpu_submission_span_max_batch_ms=%.3f frame_budget_90hz_ms=11.111\n", static_cast(GpuFarTilesSubmitted), static_cast(GpuFarSubmissionBatches),GpuFarMaxTilesPerSubmissionBatch, GpuFarPoolReserveMs,GpuFarPreparationWallMs,GpuFarPreparationWorkerMs, GpuFarEnqueueWallSeconds*1000.0, GpuFarGpuDispatchMs,AverageGpuMs,GpuFarGpuDispatchMaxMs, GpuFarSubmissionSpanMs,GpuFarSubmissionSpanMaxMs); std::printf("[GpuFarTimeline] pump_calls=%llu pump_first_ms=%.3f pump_last_ms=%.3f pump_gap_sum_ms=%.3f pump_gap_max_ms=%.3f pump_cpu_sum_ms=%.3f pump_cpu_max_ms=%.3f submit_first_ms=%.3f submit_last_ms=%.3f completion_polls=%llu completion_first_ms=%.3f completion_last_ms=%.3f queue_envelope_ms=%.3f gpu_busy_ms=%.3f estimated_idle_or_poll_ms=%.3f\n", static_cast(GpuFarPumpCalls),GpuFarFirstPumpMs,GpuFarLastPumpMs, GpuFarPumpGapMs,GpuFarPumpGapMaxMs,GpuFarPumpWallMs,GpuFarPumpMaxWallMs, GpuFarFirstSubmitMs,GpuFarLastSubmitMs, static_cast(GpuFarCompletionPolls),GpuFarFirstCompletionPollMs, GpuFarLastCompletionPollMs, GpuFarFirstSubmitMs>=0.0&&GpuFarLastCompletionPollMs>=0.0 ?GpuFarLastCompletionPollMs-GpuFarFirstSubmitMs:0.0, GpuFarSubmissionSpanMs, GpuFarFirstSubmitMs>=0.0&&GpuFarLastCompletionPollMs>=0.0 ?std::max(0.0,GpuFarLastCompletionPollMs-GpuFarFirstSubmitMs-GpuFarSubmissionSpanMs):0.0); 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 { double CpuMeshWorkerSeconds=0.0; uint64 CpuMeshTiles=0; for(int32 Level=0;Level<=MaxLevels;++Level) { CpuMeshWorkerSeconds+=WorkerSecondsByLevel[Level]; CpuMeshTiles+=GeneratedByLevel[Level]; } std::printf("[GpuFarModeTiming] mode=cpu cpu_mesh_tiles=%llu cpu_mesh_worker_sum_s=%.6f whole_view_wall_s=%.6f\n", static_cast(CpuMeshTiles),CpuMeshWorkerSeconds,Elapsed); } ReportTileTimings(); if(GpuFarOutputCountChecks>0) std::printf("[GpuFarSlotCapacitySummary] checked_tiles=%llu surface_overflow_tiles=%llu panel_overflow_tiles=%llu count_readback_failures=%llu capacity_vertices=%u max_required_vertices=%u max_key=(%d,%d,%d,lod%d) max_slot=%u check_path=normal_after_completion_event\n", static_cast(GpuFarOutputCountChecks), static_cast(GpuFarOutputOverflowCount), static_cast(GpuFarConnectorOverflowCount), static_cast(GpuFarOutputCountReadbackFailures), VoxelForgeGpuFarViewer::PooledOutputVertexCapacityPerTile, GpuFarMaxRequiredVertices,GpuFarMaxRequiredVertexKey.Coord.X, GpuFarMaxRequiredVertexKey.Coord.Y,GpuFarMaxRequiredVertexKey.Coord.Z, GpuFarMaxRequiredVertexKey.Level,GpuFarMaxRequiredOutputSlot); std::fflush(stdout); if(bQuitAfterClipmap&&CapturePath.empty() &&(!bGpuFarEnabled||!bGpuFarShaderPrewarm||bGpuWarmupCompleted)) { bQuitAfterClipmapClosePosted=true; PostMessageA(Window,WM_CLOSE,0,0); } } if(bInitialClipmapReported&&bGpuFarAuditEnabled&&GpuFarAudit&&!bGpuFarAuditReported) { GpuFarAudit->Finalize();GpuFarAudit->Print(); bGpuFarAuditReported=true; std::printf("[GpuFarSurvivalAudit] mesh_source=GPU field_readback=required status=%s\n", GpuFarAudit->Passing()?"PASS":"FAIL"); std::fflush(stdout); if(bQuitAfterClipmap&&CapturePath.empty())PostMessageA(Window,WM_CLOSE,0,0); } bGenerationRunning=DesiredResidentCount!=DesiredTiles.size()||!DirtyBatchSet.empty() ||(bGpuFarEnabled&&!GpuFarQueue.empty()); } void CaptureRenderedFrame() { // Capturer le vol dans la boucle de rendu conserve les transitions LOD. // Capture the flight inside the render loop to retain LOD transition frames. if(!FlightCaptureSequencePrefix.empty()&&bFlightStarted) { static constexpr std::array CaptureSeconds={0.1,5.0,15.0,25.0,32.0}; const double FlightElapsed=std::chrono::duration( std::chrono::steady_clock::now()-FlightStartTime).count(); if(FlightCaptureSequenceIndex(CaptureSeconds.size()) &&FlightElapsed>=CaptureSeconds[FlightCaptureSequenceIndex]) { char Suffix[16]{}; std::snprintf(Suffix,sizeof(Suffix),"_%02d.png",FlightCaptureSequenceIndex); const std::string Path=FlightCaptureSequencePrefix+Suffix; if(SaveBackBufferPng(Path)) std::printf("[FlightSequenceCapture] index=%d elapsed_s=%.3f path=%s\n", FlightCaptureSequenceIndex,FlightElapsed,Path.c_str()); else std::fprintf(stderr,"[FlightSequenceCapture] index=%d failed path=%s\n", FlightCaptureSequenceIndex,Path.c_str()); ++FlightCaptureSequenceIndex; std::fflush(stdout); } } const bool bReadyToCapture=bCaptureAfterClipmap?bInitialClipmapReported:IsFullDetailUploaded(); if(CapturePath.empty()||bAutoCaptureWritten||!bReadyToCapture)return; bAutoCaptureWritten=SaveBackBufferPng(CapturePath); if(bAutoCaptureWritten) { const double Elapsed=std::chrono::duration(std::chrono::steady_clock::now()-GenerationStart).count(); std::printf("Back-buffer capture saved: %s (%.3f s after generation start; full detail uploaded).\n",CapturePath.c_str(),Elapsed); std::fflush(stdout);PostMessageA(Window,WM_CLOSE,0,0); } else std::fprintf(stderr,"Back-buffer capture failed: %s\n",CapturePath.c_str()); } void Capture(bool bOn) { bCaptured=bOn; if(bOn){SetCapture(Window);ShowCursor(FALSE);GetCursorPos(&LastMouse);POINT C{Width/2,Height/2};ClientToScreen(Window,&C);SetCursorPos(C.x,C.y);} else{ReleaseCapture();ShowCursor(TRUE);} } void UpdateTitle() { 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 "<(FrameOrdinal),ColdTimelineMilliseconds(DrawStart), LastDrawEndAt.time_since_epoch().count()!=0 ?std::chrono::duration(DrawStart-LastDrawEndAt).count():0.0); const double InterDrawGapMs=LastDrawEndAt.time_since_epoch().count()!=0 ?std::chrono::duration(DrawStart-LastDrawEndAt).count():0.0; PumpGeneration(); const auto CpuPumpEnd=std::chrono::steady_clock::now(); const bool bDeferGpuUntilCpuFrame=bGpuFarEnabled&&bPresentCpuFrameBeforeGpu &&!bCpuReadyFramePresentedBeforeGpu; 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( 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) { bFlightStarted=true;FlightStartTime=Now;FlightStartPosition=Position; FlightStartCrossingIndex=CrossingIndex;FlightObservedCrossings=0; bFlightCrossingsValid=true; std::printf("[FlightBenchmarkStart] crossings=%d speed=%.2fm/s direction=+Y start=(%.2f,%.2f,%.2f)m cache_mode=none\n", FlightTargetCrossings,FlightSpeedMps,Position.X,Position.Y,Position.Z); std::fflush(stdout); } if(FlightTargetCrossings>0&&bFlightStarted&&!bFlightFinished) { const double Elapsed=std::chrono::duration(Now-FlightStartTime).count(); Position=V3(FlightStartPosition.X,FlightStartPosition.Y+ static_cast(FlightSpeedMps*Elapsed),FlightStartPosition.Z); if(FlightObservedCrossings>=FlightTargetCrossings) { bFlightFinished=true; std::printf("[FlightBenchmarkMove] movement stopped after %d center-chunk crossings; waiting for new nearest tiles, meshes and uploads.\n", FlightObservedCrossings); std::fflush(stdout); } } const float Dt=std::clamp(std::chrono::duration(Now-PreviousFrame).count(),0.0f,0.1f); PreviousFrame=Now;FrameMs=Dt*1000.0; const V3 F=Forward(),R=Normalize(Cross(F,{0,0,1})),U=Normalize(Cross(R,F)); const float Step=MoveSpeed*Dt*(Keys[VK_SHIFT]?4.0f:1.0f); if(Keys['W'])Position=Add(Position,Mul(F,Step));if(Keys['S'])Position=Sub(Position,Mul(F,Step)); if(Keys['A'])Position=Sub(Position,Mul(R,Step));if(Keys['D'])Position=Add(Position,Mul(R,Step)); if(Keys[VK_SPACE]||Keys['E'])Position.Z+=Step;if(Keys[VK_CONTROL]||Keys['Q'])Position.Z-=Step; if(Streamer&&NeedsRecenter(BuildTargetChunk))RecenterStreaming(); const float Clear[4]={0.055f,0.075f,0.105f,1.0f}; Context->OMSetRenderTargets(1,&RenderTarget,DepthView);Context->ClearRenderTargetView(RenderTarget,Clear); Context->ClearDepthStencilView(DepthView,D3D11_CLEAR_DEPTH,1.0f,0); D3D11_VIEWPORT Viewport{0,0,static_cast(Width),static_cast(Height),0,1};Context->RSSetViewports(1,&Viewport); Context->RSSetState(bWireframe?WireRasterizer:SolidRasterizer);Context->IASetInputLayout(InputLayout); Context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); FConstants C{};const M4 V=View(Position,F,R,U);const M4 P=Perspective(1.04719755f,static_cast(Width)/std::max(1,Height),0.05f,5000.0f); M4 Combined{};for(int I=0;I<4;++I)for(int J=0;J<4;++J)for(int K=0;K<4;++K)Combined.M[I][J]+=V.M[I][K]*P.M[K][J]; C.ViewProjection=Transpose(Combined);C.Camera[0]=Position.X;C.Camera[1]=Position.Y;C.Camera[2]=Position.Z; C.Forward[0]=F.X;C.Forward[1]=F.Y;C.Forward[2]=F.Z;C.LightDirection[0]=-0.5f;C.LightDirection[1]=-0.72f;C.LightDirection[2]=-0.48f; C.FogStart=260.0f;C.FogEnd=2600.0f;C.Ambient=0.36f; C.Padding[0]=1.0f; Context->UpdateSubresource(Constants,0,nullptr,&C,0,0);Context->VSSetConstantBuffers(0,1,&Constants);Context->PSSetConstantBuffers(0,1,&Constants); Context->VSSetShader(VertexShader,nullptr,0);Context->PSSetShader(PixelShader,nullptr,0); for(const auto& Pair:StreamingBatches) { const FStreamingGpuBatch& L=Pair.second; if(!bShowLevel[Pair.first.Level] ||(CaptureOnlyLod>=0&&Pair.first.Level!=CaptureOnlyLod) ||!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); 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 // ready the pooled GPU meshes draw directly as before. if(bGpuFarEnabled&&ShapeWorld&&ShapeWorld->hasFarWorld()) { C.Padding[0]=0.01f; Context->UpdateSubresource(Constants,0,nullptr,&C,0,0); Context->VSSetConstantBuffers(0,1,&Constants);Context->PSSetConstantBuffers(0,1,&Constants); for(auto& Pair:GpuFarTiles) { FGpuFarTile& Tile=Pair.second; 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; if(!IsRenderedTileReady(Pair.first))continue; const bool bDepthDisabledAudit=bGpuFarDepthDisabledAudit&&bDrawOnlyTile &&IsDrawOnlyTile(Pair.first); if(bDepthDisabledAudit) { Context->OMSetDepthStencilState(DepthDisabledAuditState,0); if(!bGpuFarDepthDisabledAuditReported) { bGpuFarDepthDisabledAuditReported=true; std::printf("[GpuFarDepthDisabledAudit] key=(%d,%d,%d,lod%d) depth_test=disabled path=gpu_tile_draw\n", Pair.first.Coord.X,Pair.first.Coord.Y,Pair.first.Coord.Z,Pair.first.Level); } } const bool bDrawReadbackCopy=(bGpuFarReadbackCopyDrawAudit||bGpuFarMeterCopyDrawAudit ||bGpuFarCpuMeshDrawAudit) &&bDrawOnlyTile &&IsDrawOnlyTile(Pair.first)&&Tile.ReadbackCopyVertexBuffer &&Tile.ReadbackCopyIndexBuffer; const bool bForceDirectDraw=bGpuFarDirectDrawAudit&&bDrawOnlyTile &&IsDrawOnlyTile(Pair.first); uint32 DirectDrawArgs[11]{}; if(bAuditGpuSkirtDrawArgs&&!Tile.bSkirtDrawArgsAudited &&(Tile.VisibleSkirtFaceMask!=0||(bDrawOnlyTile&&IsDrawOnlyTile(Pair.first)))) { if(!GpuSkirtArgsStaging) { D3D11_BUFFER_DESC StagingDesc{}; StagingDesc.ByteWidth=VoxelForgeGpuFarViewer::PooledOutputArgsDwordsPerTile*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(CreateResult)); } if(GpuSkirtArgsStaging) { const D3D11_BOX ArgsSource{Tile.IndirectArgsByteOffset,0,0, Tile.IndirectArgsByteOffset +VoxelForgeGpuFarViewer::PooledOutputArgsDwordsPerTile*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(ArgsMapped.pData); if(bForceDirectDraw)std::copy_n(Args,11,DirectDrawArgs); const uint32 LocalOutputSlot=Tile.IndirectArgsByteOffset /(VoxelForgeGpuFarViewer::PooledOutputArgsDwordsPerTile*sizeof(uint32)); const uint32 ExpectedStartIndex=LocalOutputSlot*32768u; const uint32 ExpectedSurfaceStartIndex=LocalOutputSlot *VoxelForgeGpuFarViewer::PooledOutputVertexCapacityPerTile; ++GpuSkirtDrawAuditTiles; GpuSkirtDrawAuditSumIndices+=Args[5]; GpuSkirtDrawAuditMaxIndices=std::max(GpuSkirtDrawAuditMaxIndices,Args[5]); if(Args[5]==0)++GpuSkirtDrawAuditZeroCounts; if(Args[10]!=0)++GpuSkirtDrawAuditOverflow; if(Args[7]!=ExpectedStartIndex)++GpuSkirtDrawAuditBadStartIndex; if(Args[0]%3u!=0||Args[0]>VoxelForgeGpuFarViewer::PooledOutputVertexCapacityPerTile ||Args[1]!=1u||Args[2]!=ExpectedSurfaceStartIndex ||Args[3]!=0u||Args[4]!=0u) ++GpuSkirtDrawAuditBadSurfaceArgs; std::printf("[GpuSkirtDrawArgs] key=(%d,%d,%d,lod%d) face_mask=0x%02x output_slot=%u surface_indices=%u surface_instances=%u surface_start_index=%u expected_surface_start_index=%u surface_base_vertex=%u surface_start_instance=%u skirt_panel_indices=%u connector_start_index=%u expected_connector_start_index=%u overflow=%u\n", Pair.first.Coord.X,Pair.first.Coord.Y,Pair.first.Coord.Z,Pair.first.Level, static_cast(Tile.VisibleSkirtFaceMask),Tile.OutputSlot, Args[0],Args[1],Args[2],ExpectedSurfaceStartIndex,Args[3],Args[4], Args[5],Args[7],ExpectedStartIndex,Args[10]); Context->Unmap(GpuSkirtArgsStaging,0); } else std::fprintf(stderr,"[GpuSkirtDrawAuditError] map_staging_hr=0x%08lx\n", static_cast(MapResult)); } Tile.bSkirtDrawArgsAudited=true; } const UINT Stride=bDrawReadbackCopy?sizeof(FGpuVertex):32,Offset=0; if(bDrawReadbackCopy) { if(bGpuFarMeterCopyDrawAudit||bGpuFarCpuMeshDrawAudit) { C.Padding[0]=1.0f; Context->UpdateSubresource(Constants,0,nullptr,&C,0,0); Context->VSSetConstantBuffers(0,1,&Constants); Context->PSSetConstantBuffers(0,1,&Constants); } Context->IASetVertexBuffers(0,1,&Tile.ReadbackCopyVertexBuffer,&Stride,&Offset); Context->IASetIndexBuffer(Tile.ReadbackCopyIndexBuffer,DXGI_FORMAT_R32_UINT,0); Context->DrawIndexed(Tile.ReadbackCopyIndexCount,0,0); } else { Context->IASetVertexBuffers(0,1,&Tile.VertexBuffer,&Stride,&Offset); Context->IASetIndexBuffer(Tile.IndexBuffer,DXGI_FORMAT_R32_UINT,0); if(bForceDirectDraw) { if(DirectDrawArgs[0]&&DirectDrawArgs[1]) Context->DrawIndexed(DirectDrawArgs[0],DirectDrawArgs[2], static_cast(DirectDrawArgs[3])); if(DirectDrawArgs[5]&&Tile.ConnectorVertexBuffer&&Tile.ConnectorIndexBuffer) { Context->IASetVertexBuffers(0,1,&Tile.ConnectorVertexBuffer,&Stride,&Offset); Context->IASetIndexBuffer(Tile.ConnectorIndexBuffer,DXGI_FORMAT_R32_UINT,0); Context->DrawIndexed(DirectDrawArgs[5],DirectDrawArgs[7], static_cast(DirectDrawArgs[8])); } std::printf("[GpuDirectDrawAudit] key=(%d,%d,%d,lod%d) surface_indices=%u surface_start_index=%u surface_base_vertex=%u panel_plus_skirt_indices=%u connector_start_index=%u path=direct\n", Pair.first.Coord.X,Pair.first.Coord.Y,Pair.first.Coord.Z,Pair.first.Level, DirectDrawArgs[0],DirectDrawArgs[2],DirectDrawArgs[3],DirectDrawArgs[5],DirectDrawArgs[7]); } else { Context->DrawIndexedInstancedIndirect(Tile.IndirectArgs,Tile.IndirectArgsByteOffset); if(Tile.ConnectorVertexBuffer&&Tile.ConnectorIndexBuffer) { Context->IASetVertexBuffers(0,1,&Tile.ConnectorVertexBuffer,&Stride,&Offset); Context->IASetIndexBuffer(Tile.ConnectorIndexBuffer,DXGI_FORMAT_R32_UINT,0); Context->DrawIndexedInstancedIndirect(Tile.IndirectArgs, Tile.IndirectArgsByteOffset+5u*sizeof(uint32)); } } } if(bDepthDisabledAudit)Context->OMSetDepthStencilState(nullptr,0); } } if(bAuditGpuSkirtDrawArgs&&bInitialClipmapReported&&!bGpuSkirtDrawAuditReported) { std::printf("[GpuSkirtDrawArgsSummary] tiles=%llu zero_index_counts=%llu overflow=%llu bad_surface_args=%llu bad_connector_start_indices=%llu total_panel_plus_skirt_indices=%llu max_panel_plus_skirt_indices=%llu status=%s\n", static_cast(GpuSkirtDrawAuditTiles), static_cast(GpuSkirtDrawAuditZeroCounts), static_cast(GpuSkirtDrawAuditOverflow), static_cast(GpuSkirtDrawAuditBadSurfaceArgs), static_cast(GpuSkirtDrawAuditBadStartIndex), static_cast(GpuSkirtDrawAuditSumIndices), static_cast(GpuSkirtDrawAuditMaxIndices), (GpuSkirtDrawAuditTiles>0&&GpuSkirtDrawAuditOverflow==0 &&GpuSkirtDrawAuditBadStartIndex==0&&GpuSkirtDrawAuditBadSurfaceArgs==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( 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( bGpuFarEnabled&&!bDisableGpuColdStartDrain?1:11)); LastDrawEndAt=std::chrono::steady_clock::now(); if(bTraceColdFrame) std::printf("[ColdFrame] stage=end frame=%llu at_ms=%.3f cpu_pump_ms=%.3f gpu_pump_ms=%.3f held=1 present_ms=0.000\n", static_cast(FrameOrdinal),ColdTimelineMilliseconds(LastDrawEndAt), std::chrono::duration(CpuPumpEnd-DrawStart).count(), std::chrono::duration(GpuPumpEnd-CpuPumpEnd).count()); return; } if(bGpuFarEnabled&&bGpuFarShaderPrewarm&&!bGpuWarmupDeferredUntilFirstView &&!bGpuWarmupCompleted &&!bGpuShaderWarmupQueueFinished.load(std::memory_order_acquire)) { if(!bGpuWarmupPresentSkipReported) { bGpuWarmupPresentSkipReported=true; std::printf("[GpuWarmupPresentSkip] begin_ms=%.3f policy=skip_present_while_cold_shader_queue_is_pending\n", std::chrono::duration( std::chrono::steady_clock::now()-ColdProcessStart).count()); std::fflush(stdout); } std::this_thread::sleep_for(std::chrono::milliseconds(1)); LastDrawEndAt=std::chrono::steady_clock::now(); if(bTraceColdFrame) std::printf("[ColdFrame] stage=end frame=%llu at_ms=%.3f cpu_pump_ms=%.3f gpu_pump_ms=%.3f held=1 present_ms=0.000 warmup_queue_pending=1\n", static_cast(FrameOrdinal),ColdTimelineMilliseconds(LastDrawEndAt), std::chrono::duration(CpuPumpEnd-DrawStart).count(), std::chrono::duration(GpuPumpEnd-CpuPumpEnd).count()); return; } const auto BeforePresent=std::chrono::steady_clock::now(); 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(); // The CPU-ready frame is the ownership handoff gate for this route. // Keep that one presentation, then suppress presents while GPU work runs. const bool bDidPresent=!bGpuFarNoPresent||bDeferGpuUntilCpuFrame; const HRESULT PresentResult=bDidPresent ?SwapChain->Present(PresentSyncInterval,PresentFlags):S_FALSE; const auto PresentCallEnd=std::chrono::steady_clock::now(); if(!bDidPresent&&!bGpuFarNoPresentReported) { bGpuFarNoPresentReported=true; std::printf("[GpuPresentationControl] mode=no_present_after_cpu_handoff first_skipped_frame_ms=%.3f render_commands_still_submitted=1 gpu_tiles_submitted=%llu\n", ColdTimelineMilliseconds(PresentCallEnd), static_cast(GpuFarTilesSubmitted)); std::fflush(stdout); } if(bDidPresent&&GpuFarTilesSubmitted>0&&!bGpuFirstBackedPresentReported) { bGpuFirstBackedPresentReported=true; std::printf("[GpuFirstBackedPresent] at_ms=%.3f call_ms=%.3f sync=%u flags=0x%08x hr=0x%08lx submitted_tiles=%llu batches=%llu\n", std::chrono::duration(PresentCallEnd-ColdProcessStart).count(), std::chrono::duration(PresentCallEnd-PresentCallStart).count(), PresentSyncInterval,PresentFlags,static_cast(PresentResult), static_cast(GpuFarTilesSubmitted), static_cast(GpuFarSubmissionBatches)); std::fflush(stdout); } if(bDidPresent&&bInitialClipmapReported&&!bWholeViewPresented) { bWholeViewPresented=true; std::printf("[WholeViewPresented] at_ms=%.3f present_ms=%.3f sync=%u hr=0x%08lx\n", std::chrono::duration(PresentCallEnd-ColdProcessStart).count(), std::chrono::duration(PresentCallEnd-PresentCallStart).count(), PresentSyncInterval,static_cast(PresentResult)); std::fflush(stdout); } if(bDidPresent&&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(PresentCallEnd-ColdProcessStart).count(), std::chrono::duration(PresentCallEnd-PresentCallStart).count(), PresentSyncInterval,static_cast(PresentResult)); std::fflush(stdout); } const uint64 PresentOrdinal=bDidPresent?++PresentCallCount:0; if(bDidPresent&&bNonBlockingStartupPresent) { ++StartupNonBlockingPresentCalls; if(PresentResult==DXGI_ERROR_WAS_STILL_DRAWING)++StartupNonBlockingPresentSkips; else if(FAILED(PresentResult)) std::fprintf(stderr,"[PresentStartupError] hr=0x%08lx\n", static_cast(PresentResult)); } if(bDidPresent&&PresentOrdinal<=3) 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(PresentOrdinal), std::chrono::duration(PresentCallEnd-ColdProcessStart).count(), PresentSyncInterval,PresentFlags,bNonBlockingStartupPresent?"startup-do-not-wait":"normal", static_cast(PresentResult), std::chrono::duration(PresentCallEnd-PresentCallStart).count(), static_cast(GpuFarTilesSubmitted), static_cast(GpuFarSubmissionBatches)); if(bDidPresent&&bDeferGpuUntilCpuFrame&&!StreamingBatches.empty()) { bCpuReadyFramePresentedBeforeGpu=true; CpuReadyFrameBeforeGpuAt=PresentCallEnd; std::printf("[CpuReadyFrameBeforeGpu] at_ms=%.3f uploaded_cpu_batches=%zu next_action=submit_gpu_far\n", std::chrono::duration(PresentCallEnd-ColdProcessStart).count(), StreamingBatches.size()); std::fflush(stdout); } UpdateTitle(); const auto DrawEnd=std::chrono::steady_clock::now(); const double CpuPumpMs=std::chrono::duration(CpuPumpEnd-DrawStart).count(); const double GpuPumpMs=std::chrono::duration(GpuPumpEnd-CpuPumpEnd).count(); const double PresentCallMs=std::chrono::duration(PresentCallEnd-PresentCallStart).count(); const double TitleMs=std::chrono::duration(DrawEnd-PresentCallEnd).count(); const double RenderPresentMs=PresentCallMs+TitleMs; if(InterDrawGapMs>50.0||CpuPumpMs>50.0||GpuPumpMs>50.0||RenderPresentMs>50.0) std::printf("[LongViewerFrame] at_ms=%.3f inter_draw_gap_ms=%.3f cpu_pump_ms=%.3f gpu_pump_ms=%.3f pre_present_ms=%.3f present_sync=%u present_call_ms=%.3f title_ms=%.3f\n", std::chrono::duration(DrawStart-ColdProcessStart).count(), InterDrawGapMs,CpuPumpMs,GpuPumpMs, std::chrono::duration(BeforePresent-GpuPumpEnd).count(), PresentSyncInterval,PresentCallMs,TitleMs); if(bTraceColdFrame) std::printf("[ColdFrame] stage=end frame=%llu at_ms=%.3f cpu_pump_ms=%.3f gpu_pump_ms=%.3f pre_present_ms=%.3f present_ms=%.3f present_sync=%u present_hr=0x%08lx held=0\n", static_cast(FrameOrdinal),ColdTimelineMilliseconds(DrawEnd), CpuPumpMs,GpuPumpMs, std::chrono::duration(BeforePresent-GpuPumpEnd).count(), PresentCallMs,PresentSyncInterval,static_cast(PresentResult)); LastDrawEndAt=DrawEnd; if(bQuitAfterClipmap&&CapturePath.empty()&&bInitialClipmapReported &&(!bGpuFarEnabled||!bGpuFarShaderPrewarm||bGpuWarmupCompleted) &&!bQuitAfterClipmapClosePosted) { bQuitAfterClipmapClosePosted=true; PostMessageA(Window,WM_CLOSE,0,0); } } }; FApp* GApp=nullptr; LRESULT CALLBACK WindowProc(HWND H,UINT Message,WPARAM W,LPARAM L) { if(!GApp)return DefWindowProc(H,Message,W,L); switch(Message) { case WM_SIZE: if(W!=SIZE_MINIMIZED) { const UINT NewWidth=LOWORD(L),NewHeight=HIWORD(L); const bool bResizeNeeded=static_cast(NewWidth)!=GApp->Width ||static_cast(NewHeight)!=GApp->Height; const auto ResizeStart=std::chrono::steady_clock::now(); if(bResizeNeeded)GApp->Resize(NewWidth,NewHeight); std::printf("[ColdTimeline] event=viewer_window_size width=%u height=%u resized=%s duration_ms=%.3f\n", NewWidth,NewHeight,bResizeNeeded?"yes":"no", std::chrono::duration( std::chrono::steady_clock::now()-ResizeStart).count()); } return 0; case WM_KEYDOWN: { const bool bWasDown=(L&(1ll<<30))!=0;if(W<256)GApp->Keys[W]=true; if(W==VK_ESCAPE){if(GApp->bCaptured)GApp->Capture(false);else DestroyWindow(H);} if(!bWasDown&&W=='F')GApp->bWireframe=!GApp->bWireframe; if(!bWasDown&&W=='T'){GApp->bRoundTunnels=!GApp->bRoundTunnels;GApp->bRebuildPending=true;} if(!bWasDown&&W=='V'){GApp->bShapeWorld=!GApp->bShapeWorld;GApp->bRebuildPending=true;} if(!bWasDown&&W=='G'&&GApp->bRoundTunnels) { GApp->bRoundTunnelEnhanced=!GApp->bRoundTunnelEnhanced; GApp->bRebuildPending=true; std::printf("Round-tunnel comparison: %s wall field.\n", GApp->bRoundTunnelEnhanced?"detailed/smoothed":"legacy smooth tube"); } if(!bWasDown&&W=='H')GApp->ToggleFarRenderer(); if(!bWasDown&&(W=='N'||W=='P'))GApp->RequestSeed(W=='N'?1:-1); if(!bWasDown&&W>='1'&&W<='8'){const int32 I=static_cast(W-'1');GApp->bShowLevel[I]=!GApp->bShowLevel[I];} if(!bWasDown&&W=='9')GApp->bShowLevel[8]=!GApp->bShowLevel[8]; if(!bWasDown&&W=='0')for(bool& B:GApp->bShowLevel)B=!B; return 0; } case WM_KEYUP:if(W<256)GApp->Keys[W]=false;return 0; case WM_RBUTTONDOWN:GApp->Capture(true);return 0; case WM_RBUTTONUP:GApp->Capture(false);return 0; case WM_MOUSEMOVE: if(GApp->bCaptured){POINT C{GApp->Width/2,GApp->Height/2};ClientToScreen(H,&C);POINT P{GET_X_LPARAM(L),GET_Y_LPARAM(L)},Screen=P;ClientToScreen(H,&Screen);const int32 DX=Screen.x-C.x,DY=Screen.y-C.y;if(DX||DY){GApp->Yaw+=DX*0.0035f;GApp->Pitch=std::clamp(GApp->Pitch-DY*0.0035f,-1.55f,1.55f);SetCursorPos(C.x,C.y);}}return 0; case WM_MOUSEWHEEL:GApp->MoveSpeed=std::clamp(GApp->MoveSpeed*(GET_WHEEL_DELTA_WPARAM(W)>0?1.25f:0.8f),0.25f,1000.0f);return 0; case WM_DESTROY:if(GApp->Streamer)GApp->Streamer->Stop();PostQuitMessage(0);return 0; } return DefWindowProc(H,Message,W,L); } std::filesystem::path DefaultDataPath() { wchar_t Module[MAX_PATH]{};GetModuleFileNameW(nullptr,Module,MAX_PATH); const std::filesystem::path Exe(Module); return Exe.parent_path().parent_path()/L"data"/L"owner_world.json"; } int RunTileBenchmark(FStandaloneOwnerWorld& World,V3 CameraPosition,int32 Level, int32 Count,bool bProfile,bool bCompareEvaluators,bool bDensityHash, VoxelForgeCore::World* CoreWorld) { const FVector CameraVoxels(CameraPosition.X*4.0,CameraPosition.Y*4.0,CameraPosition.Z*4.0); const FStandaloneDesiredTileSet Desired=StandaloneWorldMesher::BuildDesiredSet(World,CameraVoxels); std::vector Tiles;Tiles.reserve(static_cast(std::max(Count,1))); if(CoreWorld) { const auto CoreTiles=CoreWorld->desiredTiles({CameraVoxels.X,CameraVoxels.Y,CameraVoxels.Z}); for(const auto& Key:CoreTiles) if(Key.lod==Level&&static_cast(Tiles.size())(Tiles.size())(World.SkirtCells);Mesher.LODOctaveDrop=World.LODOctaveDrop; const int32 BandMin=World.StrateContentCutMinLevel<9&&Desired.bHasStrate ?Desired.StrateBottomChunkZ*CHUNK_SIZE:MIN_int32; const int32 BandMax=World.StrateContentCutMinLevel<9&&Desired.bHasStrate ?(Desired.StrateTopChunkZ+1)*CHUNK_SIZE:MAX_int32; if(bCompareEvaluators) { const bool bOriginalFused=VoxelGenLOD::IsUseFusedEvaluatorEnabled(); uint64 Mismatches=0,ComparedSamples=0,MeshCountMismatches=0; float MaxAbsoluteDifference=0.0f; size_t FirstMismatch=SIZE_MAX; FVoxelTileKey FirstMismatchTile{}; VoxelGenLOD::SetUseFusedEvaluatorEnabled(true); for(const FVoxelTileKey& Tile:Tiles) { const int32 Cells=Level FusedDensities,OpStackDensities; int64 FusedSampleCalls=0,OpStackSampleCalls=0; FVoxelMeshData FusedMesh=Mesher.GenerateMesh(Tile.OriginVoxels(),Step,Cells,nullptr, BandMin,BandMax,&FusedSampleCalls,nullptr,nullptr,&FusedDensities); VoxelGenLOD::SetUseFusedEvaluatorEnabled(false); FVoxelMeshData OpStackMesh=Mesher.GenerateMesh(Tile.OriginVoxels(),Step,Cells,nullptr, BandMin,BandMax,&OpStackSampleCalls,nullptr,nullptr,&OpStackDensities); VoxelGenLOD::SetUseFusedEvaluatorEnabled(true); if(FusedMesh.Vertices.Num()!=OpStackMesh.Vertices.Num() || FusedMesh.Triangles.Num()!=OpStackMesh.Triangles.Num())++MeshCountMismatches; const size_t SharedSamples=std::min(FusedDensities.size(),OpStackDensities.size()); ComparedSamples+=SharedSamples; for(size_t I=0;I(FusedDensities[I])!=std::bit_cast(OpStackDensities[I])) { if(FirstMismatch==SIZE_MAX){FirstMismatch=I;FirstMismatchTile=Tile;} ++Mismatches; MaxAbsoluteDifference=std::max(MaxAbsoluteDifference, std::abs(FusedDensities[I]-OpStackDensities[I])); } } Mismatches+=static_cast(std::max(FusedDensities.size(),OpStackDensities.size())-SharedSamples); } std::printf("[EvaluatorCompare] LOD=%d tiles=%zu compared_samples=%llu density_mismatches=%llu first_tile=(%d,%d,%d) first_index=%llu max_abs=%.9g mesh_count_mismatch_tiles=%llu original_fused=%d\n", Level,Tiles.size(),static_cast(ComparedSamples), static_cast(Mismatches), FirstMismatchTile.Coord.X,FirstMismatchTile.Coord.Y,FirstMismatchTile.Coord.Z, static_cast(FirstMismatch),MaxAbsoluteDifference, static_cast(MeshCountMismatches),bOriginalFused?1:0); VoxelGenLOD::SetUseFusedEvaluatorEnabled(bOriginalFused); std::fflush(stdout); return Mismatches==0?0:5; } std::vector TileSeconds;TileSeconds.reserve(Tiles.size()); uint64 Samples=0,Vertices=0,Indices=0; uint64 DensityHash=14695981039346656037ull; const auto TotalStart=std::chrono::steady_clock::now(); for(const FVoxelTileKey& Tile:Tiles) { const auto TileStart=std::chrono::steady_clock::now(); const int32 Cells=Level DebugDensitySamples; uint64 TileVertices=0,TileIndices=0; if(CoreWorld&&!bCompareEvaluators) { VoxelForgeCore::TileGenerationOptions Options; Options.bandMinZVoxel=BandMin;Options.bandMaxZVoxel=BandMax; Options.captureDensitySamples=bDensityHash; std::string CoreError; auto Mesh=CoreWorld->generateTile( {{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level},Options,CoreError); if(!Mesh) { std::fprintf(stderr,"[VoxelForgeCore] benchmark tile generation failed: %s\n",CoreError.c_str()); return 8; } TileSamples=static_cast(Mesh->densitySampleCount); TileVertices=Mesh->vertices.size();TileIndices=Mesh->indices.size(); if(bDensityHash)DebugDensitySamples=std::move(Mesh->debugDensitySamples); } else { FVoxelMeshData Mesh=Mesher.GenerateMesh(Tile.OriginVoxels(),Step,Cells,nullptr, BandMin,BandMax,&TileSamples,nullptr,nullptr, bDensityHash?&DebugDensitySamples:nullptr); TileVertices=static_cast(Mesh.Vertices.Num()); TileIndices=static_cast(Mesh.Triangles.Num()); } Samples+=static_cast(FMath::Max(0,TileSamples)); Vertices+=TileVertices; Indices+=TileIndices; if(bDensityHash) { for(const float Density:DebugDensitySamples) { DensityHash^=std::bit_cast(Density); DensityHash*=1099511628211ull; } } TileSeconds.push_back(std::chrono::duration( std::chrono::steady_clock::now()-TileStart).count()); } const double TotalSeconds=std::chrono::duration( std::chrono::steady_clock::now()-TotalStart).count(); const VoxelDensityProfile::FSnapshot After=VoxelDensityProfile::SnapshotCurrentThread(); std::sort(TileSeconds.begin(),TileSeconds.end()); const double Average=TotalSeconds/static_cast(Tiles.size()); std::printf("[TileBenchmark] LOD=%d generated=%zu samples=%.2fM worker_sum=%.3fs avg=%.3fms p50=%.3fms p95=%.3fms vertices=%llu indices=%llu profiling=%s\n", Level,Tiles.size(),static_cast(Samples)/1.0e6,TotalSeconds,Average*1000.0, TileSeconds[(TileSeconds.size()-1)*50/100]*1000.0, TileSeconds[(TileSeconds.size()-1)*95/100]*1000.0, static_cast(Vertices),static_cast(Indices), bProfile?"Attribution":"off"); if(bDensityHash) { std::printf("[TileDensityHash] LOD=%d tiles=%zu hash=0x%016llx\n",Level,Tiles.size(), static_cast(DensityHash)); } if(bProfile) { std::printf("[TileProfile] LOD=%d",Level); for(int32 I=0;I=Before.Cycles[I] ?After.Cycles[I]-Before.Cycles[I]:0; const double Ms=static_cast(CycleDelta) *FPlatformTime::GetSecondsPerCycle64()*1000.0; if(Ms>0.001)std::printf(" %s=%.3fms",VoxelDensityProfile::BucketName( static_cast(I)),Ms); } std::printf("\n"); const auto CounterDelta=[&](VoxelDensityProfile::ECounter Counter) { const size_t I=static_cast(Counter); return After.Counters[I]>=Before.Counters[I] ?After.Counters[I]-Before.Counters[I]:0; }; std::printf("[TileCounters] sdf_builds=%llu graph_tile_builds=%llu graph_core_builds=%llu op_block_builds=%llu\n", static_cast(CounterDelta(VoxelDensityProfile::ECounter::SdfCacheBuild)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::RoomGraphBuildGeneratorTile)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::RoomGraphBuildGeneratorTunnelCore)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::OpBlockBuilds))); std::printf("[SdfRebuildCauses] strate=%llu seed=%llu fingerprint=%llu layout=%llu manager=%llu terrain_ops=%llu fused_policy=%llu tile_policy=%llu tile_identity=%llu bounds_x=%llu bounds_y=%llu tile_window_accepted=%llu tile_window_rejected=%llu\n", static_cast(CounterDelta(VoxelDensityProfile::ECounter::SdfRebuildStrate)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::SdfRebuildSeed)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::SdfRebuildFingerprint)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::SdfRebuildLayout)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::SdfRebuildManagerLifetime)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::SdfRebuildTerrainOps)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::SdfRebuildFusedPolicy)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::SdfRebuildTilePolicy)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::SdfRebuildTileIdentity)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::SdfRebuildBoundsX)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::SdfRebuildBoundsY)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::SdfTileWindowAccepted)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::SdfTileWindowRejected))); std::printf("[TilePolicyKeyChanges] origin=%llu step=%llu cells=%llu fingerprint=%llu layout=%llu manager=%llu terrain_ops=%llu fused_path=%llu context=%llu\n", static_cast(CounterDelta(VoxelDensityProfile::ECounter::TilePolicyKeyOrigin)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::TilePolicyKeyStep)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::TilePolicyKeyCells)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::TilePolicyKeyFingerprint)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::TilePolicyKeyLayout)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::TilePolicyKeyManager)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::TilePolicyKeyTerrainOps)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::TilePolicyKeyFusedPath)), static_cast(CounterDelta(VoxelDensityProfile::ECounter::TilePolicyKeyContext))); } std::fflush(stdout); return 0; } struct FComparePoint { double X=0.0,Y=0.0,Z=0.0; }; struct FCompareBucketHash { size_t operator()(const FIntVector& K)const noexcept { uint64 H=static_cast(K.X)*0x9E3779B185EBCA87ull; H^=static_cast(static_cast(K.Y))*0xC2B2AE3D27D4EB4Full; H^=static_cast(static_cast(K.Z))*0x165667B19E3779F9ull; return static_cast(H^(H>>32)); } }; struct FDirectedSurfaceDistance { double Sum=0.0,Maximum=0.0; uint64 Count=0,Unmatched=0; }; constexpr int32 OwnerBandGrid=64; constexpr double OwnerBandSpacing=0.75; constexpr std::array OwnerBandMinWavelength={2.0,4.0,8.0,16.0}; constexpr std::array OwnerBandMaxWavelength={4.0,8.0,16.0,32.0}; void FFT64(std::array,OwnerBandGrid>& Values) { for(int32 I=1,J=0;I>1; for(;J&Bit;Bit>>=1)J^=Bit; J^=Bit; if(I(Length); const std::complex Step(std::cos(Angle),std::sin(Angle)); for(int32 Base=0;Base W(1.0,0.0); for(int32 I=0;I Even=Values[Base+I]; const std::complex Odd=Values[Base+I+Length/2]*W; Values[Base+I]=Even+Odd;Values[Base+I+Length/2]=Even-Odd;W*=Step; } } } } bool OwnerSurfaceBandRms(const std::array& Heights, const std::array& Valid,std::array& OutRms) { size_t ValidCount=0; double Sums[3][4]{}; for(int32 Y=0;Y(Y)*OwnerBandGrid+X; if(!Valid[Index])continue; ++ValidCount; const double U=(X-(OwnerBandGrid-1)*0.5)*OwnerBandSpacing; const double V=(Y-(OwnerBandGrid-1)*0.5)*OwnerBandSpacing; const double Row[3]={1.0,U,V}; for(int32 I=0;I<3;++I) { for(int32 J=0;J<3;++J)Sums[I][J]+=Row[I]*Row[J]; Sums[I][3]+=Row[I]*Heights[Index]; } } if(ValidCount(OwnerBandGrid*OwnerBandGrid*9/10))return false; for(int32 Column=0;Column<3;++Column) { int32 Pivot=Column; for(int32 Row=Column+1;Row<3;++Row) if(std::abs(Sums[Row][Column])>std::abs(Sums[Pivot][Column]))Pivot=Row; if(std::abs(Sums[Pivot][Column])<1.0e-10)return false; if(Pivot!=Column)for(int32 J=Column;J<4;++J)std::swap(Sums[Pivot][J],Sums[Column][J]); const double Scale=Sums[Column][Column]; for(int32 J=Column;J<4;++J)Sums[Column][J]/=Scale; for(int32 Row=0;Row<3;++Row)if(Row!=Column) { const double Factor=Sums[Row][Column]; for(int32 J=Column;J<4;++J)Sums[Row][J]-=Factor*Sums[Column][J]; } } const double Plane[3]={Sums[0][3],Sums[1][3],Sums[2][3]}; std::array,OwnerBandGrid>,OwnerBandGrid> Spectrum{}; double WindowSquareSum=0.0; for(int32 Y=0;Y(Y)*OwnerBandGrid+X; const double WX=0.5-0.5*std::cos(6.2831853071795864769*X/(OwnerBandGrid-1)); const double U=(X-(OwnerBandGrid-1)*0.5)*OwnerBandSpacing; const double V=(Y-(OwnerBandGrid-1)*0.5)*OwnerBandSpacing; const double Residual=Valid[Index]?Heights[Index]-(Plane[0]+Plane[1]*U+Plane[2]*V):0.0; Spectrum[Y][X]=Residual*(WX*WY); WindowSquareSum+=WX*WX*WY*WY; } FFT64(Spectrum[Y]); } for(int32 X=0;X,OwnerBandGrid> Column{}; for(int32 Y=0;Y Power{}; for(int32 Y=0;Y(OwnerBandGrid)*OwnerBandSpacing); const double FY=std::min(Y,OwnerBandGrid-Y) /(static_cast(OwnerBandGrid)*OwnerBandSpacing); const double Frequency=std::sqrt(FX*FX+FY*FY); if(Frequency<=0.0)continue; const double Wavelength=1.0/Frequency; for(size_t Band=0;Band=OwnerBandMinWavelength[Band]&&Wavelength(OwnerBandGrid*OwnerBandGrid)*WindowSquareSum; for(size_t Band=0;Band bool SampleOwnerSurfaceHeightPatch(V3 Origin,V3 Normal,V3 TangentU,V3 TangentV, TDensity&& Density,std::array& OutHeights, std::array& OutValid) { size_t ValidCount=0; for(int32 Y=0;Y(DU)),Mul(TangentV,static_cast(DV)))); double T=0.0;bool bConverged=false; for(int32 Iteration=0;Iteration<7;++Iteration) { const V3 P=Add(Base,Mul(Normal,static_cast(T))); const double D=Density(P); if(!std::isfinite(D)||std::abs(T)>16.0)break; // Core density keeps a 0.05-voxel near-zero sign margin. Accepting a // tighter root tolerance makes every otherwise-good Core patch fail. if(std::abs(D)<0.06){bConverged=true;break;} const double DP=Density(Add(Base,Mul(Normal,static_cast(T+0.5)))); const double DM=Density(Add(Base,Mul(Normal,static_cast(T-0.5)))); const double Gradient=DP-DM; if(!std::isfinite(Gradient)||std::abs(Gradient)<0.25)break; T-=std::clamp(D/Gradient,-4.0,4.0); } const size_t Index=static_cast(Y)*OwnerBandGrid+X; OutHeights[Index]=T;OutValid[Index]=bConverged?1:0; ValidCount+=bConverged?1u:0u; } return ValidCount>=static_cast(OwnerBandGrid*OwnerBandGrid*9/10); } FDirectedSurfaceDistance DirectedSurfaceDistance( const std::vector& From,const std::vector& To, double BucketWidth=1.0,int32 SearchCells=3) { FDirectedSurfaceDistance Result; if(From.empty()||To.empty()){Result.Unmatched=From.size();return Result;} std::unordered_map,FCompareBucketHash> Buckets; Buckets.reserve(To.size()); const auto BucketOf=[=](const FComparePoint& P) { return FIntVector(static_cast(std::floor(P.X/BucketWidth)), static_cast(std::floor(P.Y/BucketWidth)), static_cast(std::floor(P.Z/BucketWidth))); }; for(const FComparePoint& P:To)Buckets[BucketOf(P)].push_back(&P); for(const FComparePoint& P:From) { const FIntVector Center=BucketOf(P); double BestSquared=std::numeric_limits::infinity(); for(int32 Z=-SearchCells;Z<=SearchCells;++Z) for(int32 Y=-SearchCells;Y<=SearchCells;++Y) for(int32 X=-SearchCells;X<=SearchCells;++X) { const auto It=Buckets.find(Center+FIntVector(X,Y,Z)); if(It==Buckets.end())continue; for(const FComparePoint* Candidate:It->second) { const double DX=P.X-Candidate->X,DY=P.Y-Candidate->Y,DZ=P.Z-Candidate->Z; BestSquared=std::min(BestSquared,DX*DX+DY*DY+DZ*DZ); } } if(std::isfinite(BestSquared)) { const double Distance=std::sqrt(BestSquared); Result.Sum+=Distance;Result.Maximum=std::max(Result.Maximum,Distance);++Result.Count; } else ++Result.Unmatched; } return Result; } int RunOwnerShapeComparison(FStandaloneOwnerWorld& World,VoxelForgeCore::World& Shape, V3 CameraPosition,float CameraYaw,float CameraPitch, int32 Workers,int32 LevelFilter,int32 TileLimit, std::string_view AreaLabel,bool bCheckOwnerReliefBands) { if(!Shape.isCompiled()) {std::fprintf(stderr,"Shape comparison requires a compiled core world.\n");return 11;} if(LevelFilter>=World.FullResClipLevels&&!Shape.hasFarWorld())Shape.buildFarWorld(); const FVector CameraVoxels(CameraPosition.X*4.0,CameraPosition.Y*4.0,CameraPosition.Z*4.0); Shape.auditViewSurface({CameraVoxels.X,CameraVoxels.Y,CameraVoxels.Z},CameraYaw,CameraPitch); { const int32 Offsets[][3]={{0,0,0},{4,0,0},{-4,0,0},{0,4,0},{0,-4,0},{0,0,4},{0,0,-4}}; for(const auto& Offset:Offsets) { const float X=static_cast(CameraVoxels.X+Offset[0]); const float Y=static_cast(CameraVoxels.Y+Offset[1]); const float Z=static_cast(CameraVoxels.Z+Offset[2]); float OwnerDensity=0.0f; OwnerDensity=World.Generator->GetDensityAt(X,Y,Z); const float ShapeDensity=Shape.densityAt({X,Y,Z}); std::printf("[ShapeProbe] voxels=(%.1f,%.1f,%.1f) owner=%.5f shape=%.5f owner_air=%d shape_air=%d protected_air=%d solid_overlay=%d\n", X,Y,Z,OwnerDensity,ShapeDensity,OwnerDensity>=0.0f?1:0,ShapeDensity>=0.0f?1:0, Shape.debugCriticalAirAt({X,Y,Z})?1:0,Shape.debugSolidOverlayAt({X,Y,Z})?1:0); } } std::vector CoreDesired; for(const auto& Key:Shape.desiredTiles({CameraVoxels.X,CameraVoxels.Y,CameraVoxels.Z})) CoreDesired.emplace_back(FIntVector(Key.coordinate.x,Key.coordinate.y,Key.coordinate.z),Key.lod); std::vector Tiles; for(const FVoxelTileKey& Tile:CoreDesired) if(LevelFilter<0?Tile.Level0&&Tiles.size()>static_cast(TileLimit)) { constexpr double DegreesToRadians=3.14159265358979323846/180.0; const double YawRadians=CameraYaw*DegreesToRadians,PitchRadians=CameraPitch*DegreesToRadians; const V3 ViewForward{static_cast(std::sin(YawRadians)*std::cos(PitchRadians)), static_cast(std::cos(YawRadians)*std::cos(PitchRadians)), static_cast(std::sin(PitchRadians))}; const auto ViewScore=[&](const FVoxelTileKey& Tile) { const FIntVector O=Tile.OriginVoxels(); const V3 D{static_cast(O.X+Tile.ExtentVoxels()*0.5-CameraVoxels.X), static_cast(O.Y+Tile.ExtentVoxels()*0.5-CameraVoxels.Y), static_cast(O.Z+Tile.ExtentVoxels()*0.5-CameraVoxels.Z)}; const double Distance=std::sqrt(Dot(D,D)); // Keep near tiles first while preferring the half-space in front of this view. return Distance*Distance+32.0*std::max(0.0,Distance-Dot(D,ViewForward)); }; std::sort(Tiles.begin(),Tiles.end(),[&](const FVoxelTileKey& A,const FVoxelTileKey& B) { const double AS=ViewScore(A),BS=ViewScore(B); if(AS!=BS)return AS(TileLimit)); } if(Tiles.empty()){std::fprintf(stderr,"No tiles are available for the requested shape comparison level.\n");return 12;} struct FTileComparison { uint64 Samples=0,Changed=0,MeshMismatch=0; uint64 OldHash=14695981039346656037ull,NewHash=14695981039346656037ull; std::vector OldSurface,NewSurface; std::array OwnerBandRms{},ShapeBandRms{}; double SurfacePairDistanceVoxels=0.0; bool bHasOwnerBandPatch=false; }; std::vector Results(Tiles.size()); int32 MinChunkZ=MIN_int32,MaxChunkZ=MAX_int32,TopChunkZ=0,BottomChunkZ=0; if(World.Settings->bClampViewToStrate&&World.Manager->GetStrateChunkZBounds( StandaloneWorldMesher::CameraChunk(CameraVoxels).Z,TopChunkZ,BottomChunkZ)) {MinChunkZ=BottomChunkZ*CHUNK_SIZE;MaxChunkZ=(TopChunkZ+1)*CHUNK_SIZE;} std::atomic Next{0}; std::vector Threads; const int32 ThreadCount=std::clamp(Workers,1,16); Threads.reserve(ThreadCount); for(int32 Worker=0;Worker(World.SkirtCells); Mesher.LODOctaveDrop=World.LODOctaveDrop; for(;;) { const size_t Index=Next.fetch_add(1,std::memory_order_relaxed); if(Index>=Tiles.size())break; const FVoxelTileKey& Tile=Tiles[Index]; const int32 Cells=Tile.Level NewDensities=NewMesh?std::move(NewMesh->debugDensitySamples):std::vector{}; std::vector OldDensities; FVoxelMeshData OldMesh; OldMesh=Mesher.GenerateMesh(Tile.OriginVoxels(),Step,Cells,nullptr, MinChunkZ,MaxChunkZ,nullptr,nullptr,nullptr,&OldDensities); FTileComparison& R=Results[Index]; const size_t Shared=std::min(NewDensities.size(),OldDensities.size()); R.Samples=Shared; R.MeshMismatch=std::max(NewDensities.size(),OldDensities.size())-Shared; for(size_t I=0;I(NewDensities[I]);R.NewHash*=1099511628211ull; R.OldHash^=std::bit_cast(OldDensities[I]);R.OldHash*=1099511628211ull; } if(Tile.Level==0&&NewMesh&&OldMesh.NumSurfaceVertices>0 &&NewMesh->groups.surfaceVertexCount>0) { const int32 OldSurfaceCount=std::min(OldMesh.NumSurfaceVertices, OldMesh.Vertices.Num()); const size_t NewSurfaceCount=std::min( NewMesh->groups.surfaceVertexCount,NewMesh->vertices.size()); const FIntVector TileOrigin=Tile.OriginVoxels(); const V3 TileCenter{TileOrigin.X+Tile.ExtentVoxels()*0.5f, TileOrigin.Y+Tile.ExtentVoxels()*0.5f, TileOrigin.Z+Tile.ExtentVoxels()*0.5f}; double OwnerCenterDistanceSq=std::numeric_limits::infinity(); double ShapeCenterDistanceSq=std::numeric_limits::infinity(); V3 OwnerPoint{},OwnerNormal{},ShapePoint{},ShapeNormal{}; for(int32 OldIndex=0;OldIndex=OldMesh.Normals.Num())continue; const FVector& OP=OldMesh.Vertices[OldIndex]; const FVector& ON=OldMesh.Normals[OldIndex]; const V3 CandidatePoint{static_cast(OP.X*0.04), static_cast(OP.Y*0.04),static_cast(OP.Z*0.04)}; const V3 CandidateNormal=Normalize({static_cast(ON.X), static_cast(ON.Y),static_cast(ON.Z)}); const V3 Delta=Sub(CandidatePoint,TileCenter); const double DistanceSq=Dot(Delta,Delta); if(DistanceSqvertices[NewIndex]; const V3 CandidatePoint{static_cast(NV.position.x*0.04), static_cast(NV.position.y*0.04), static_cast(NV.position.z*0.04)}; const V3 CandidateNormal=Normalize({static_cast(NV.normal.x), static_cast(NV.normal.y),static_cast(NV.normal.z)}); if(Dot(CandidateNormal,OwnerNormal)<0.5f)continue; const V3 Delta=Sub(CandidatePoint,OwnerPoint); const double DistanceSq=Dot(Delta,Delta); if(DistanceSq=0.25f)return Normalize(Normal); const V3 GX{0.5f,0.0f,0.0f},GY{0.0f,0.5f,0.0f},GZ{0.0f,0.0f,0.5f}; return Normalize({Density(Add(Point,GX))-Density(Sub(Point,GX)), Density(Add(Point,GY))-Density(Sub(Point,GY)), Density(Add(Point,GZ))-Density(Sub(Point,GZ))}); }; const auto OwnerDensity=[&](V3 P) {return World.Generator->GetDensityAt(P.X,P.Y,P.Z);}; const auto ShapeDensity=[&](V3 P) {return Shape.densityAt({P.X,P.Y,P.Z});}; OwnerNormal=FieldNormal(OwnerPoint,OwnerNormal,OwnerDensity); ShapeNormal=FieldNormal(ShapePoint,ShapeNormal,ShapeDensity); V3 OwnerTangentU{},OwnerTangentV{},ShapeTangentU{},ShapeTangentV{}; TangentBasis(OwnerNormal,OwnerTangentU,OwnerTangentV); TangentBasis(ShapeNormal,ShapeTangentU,ShapeTangentV); std::array OwnerHeights{},ShapeHeights{}; std::array OwnerValid{},ShapeValid{}; const bool bOwnerPatch=SampleOwnerSurfaceHeightPatch(OwnerPoint, OwnerNormal,OwnerTangentU,OwnerTangentV,OwnerDensity, OwnerHeights,OwnerValid); const bool bShapePatch=SampleOwnerSurfaceHeightPatch(ShapePoint, ShapeNormal,ShapeTangentU,ShapeTangentV,ShapeDensity, ShapeHeights,ShapeValid); if(bOwnerPatch&&bShapePatch &&OwnerSurfaceBandRms(OwnerHeights,OwnerValid,R.OwnerBandRms) &&OwnerSurfaceBandRms(ShapeHeights,ShapeValid,R.ShapeBandRms)) { R.SurfacePairDistanceVoxels=std::sqrt(ShapeCenterDistanceSq); R.bHasOwnerBandPatch=true; } } } constexpr size_t VertexStride=4; if(NewMesh) { R.NewSurface.reserve(NewMesh->vertices.size()/VertexStride+1); for(size_t I=0;Ivertices.size();I+=VertexStride) {const auto& P=NewMesh->vertices[I].position;R.NewSurface.push_back({P.x*0.01,P.y*0.01,P.z*0.01});} } R.OldSurface.reserve(static_cast(OldMesh.Vertices.Num())/VertexStride+1); for(int32 I=0;I(VertexStride)) {const FVector& P=OldMesh.Vertices[I];R.OldSurface.push_back({P.X*0.01,P.Y*0.01,P.Z*0.01});} } }); } for(std::thread& Thread:Threads)Thread.join(); uint64 Samples=0,Changed=0,MeshMismatch=0; uint64 OwnerBandPatches=0; std::array OwnerBandEnergy{},ShapeBandEnergy{}; double SurfacePairDistanceSum=0.0; uint64 OldHash=14695981039346656037ull,NewHash=14695981039346656037ull; size_t OldVertexCount=0,NewVertexCount=0; std::vector OldSurface,NewSurface; for(const FTileComparison& R:Results) { Samples+=R.Samples;Changed+=R.Changed;MeshMismatch+=R.MeshMismatch; if(R.bHasOwnerBandPatch) { ++OwnerBandPatches;SurfacePairDistanceSum+=R.SurfacePairDistanceVoxels; for(size_t Band=0;Band<4;++Band) { OwnerBandEnergy[Band]+=R.OwnerBandRms[Band]*R.OwnerBandRms[Band]; ShapeBandEnergy[Band]+=R.ShapeBandRms[Band]*R.ShapeBandRms[Band]; } } OldHash^=R.OldHash;OldHash*=1099511628211ull; NewHash^=R.NewHash;NewHash*=1099511628211ull; OldVertexCount+=R.OldSurface.size();NewVertexCount+=R.NewSurface.size(); } OldSurface.reserve(OldVertexCount);NewSurface.reserve(NewVertexCount); for(FTileComparison& R:Results) { OldSurface.insert(OldSurface.end(),R.OldSurface.begin(),R.OldSurface.end()); NewSurface.insert(NewSurface.end(),R.NewSurface.begin(),R.NewSurface.end()); } const FDirectedSurfaceDistance OldToNew=DirectedSurfaceDistance(OldSurface,NewSurface,1.0,3); const FDirectedSurfaceDistance NewToOld=DirectedSurfaceDistance(NewSurface,OldSurface,1.0,3); const uint64 DistanceSamples=OldToNew.Count+NewToOld.Count; const double MeanDistance=DistanceSamples ?(OldToNew.Sum+NewToOld.Sum)/static_cast(DistanceSamples):0.0; std::printf("[OwnerShapeCompare] tiles=%zu fullres_levels=%d level_filter=%d lattice_samples=%llu changed_signs=%llu changed_share=%.6f%% old_hash=0x%016llx shape_hash=0x%016llx mesh_sample_mismatch=%llu old_surface_samples=%zu shape_surface_samples=%zu symmetric_vertex_mean_m=%.4f symmetric_vertex_max_m=%.4f unmatched_surface_samples=%llu vertex_stride=4 workers=%d\n", Tiles.size(),World.FullResClipLevels,LevelFilter,static_cast(Samples), static_cast(Changed),Samples?100.0*Changed/Samples:0.0, static_cast(OldHash),static_cast(NewHash), static_cast(MeshMismatch),OldSurface.size(),NewSurface.size(), MeanDistance,std::max(OldToNew.Maximum,NewToOld.Maximum), static_cast(OldToNew.Unmatched+NewToOld.Unmatched),ThreadCount); const std::array BandNames={"2-4","4-8","8-16","16-32"}; const std::array BandMinimumRatio={0.0,0.75,0.75,0.65}; bool bReliefBandsPass=OwnerBandPatches>0; std::printf("[OwnerReliefBandCompare] area=%.*s paired_surface_patches=%llu mean_surface_pair_distance=%.3f_vox grid=%dx%d spacing=%.2f_vox bands_rms_vox=", static_cast(AreaLabel.size()),AreaLabel.data(), static_cast(OwnerBandPatches),OwnerBandPatches ?SurfacePairDistanceSum/static_cast(OwnerBandPatches):0.0, OwnerBandGrid,OwnerBandGrid,OwnerBandSpacing); for(size_t Band=0;Band<4;++Band) { const double OwnerRms=OwnerBandPatches ?std::sqrt(OwnerBandEnergy[Band]/static_cast(OwnerBandPatches)):0.0; const double ShapeRms=OwnerBandPatches ?std::sqrt(ShapeBandEnergy[Band]/static_cast(OwnerBandPatches)):0.0; const double Ratio=OwnerRms>1.0e-5?ShapeRms/OwnerRms:0.0; std::printf("%s(owner=%.4f,shape=%.4f,ratio=%.3f)%s",BandNames[Band], OwnerRms,ShapeRms,Ratio,Band<3?" ":"\n"); if(Band>0&&OwnerRms>=0.025&&Ratio(OwnerBandPatches),bReliefBandsPass?"PASS":"FAIL", bCheckOwnerReliefBands?" (gate enabled)":" (measurement only)"); std::fflush(stdout); return Samples>0&&MeshMismatch==0&&(!bCheckOwnerReliefBands||bReliefBandsPass)?0:13; } int RunRoundWallComparison(FStandaloneOwnerWorld& World,V3 CameraPosition,int32 TileCount) { const FVector CameraVoxels(CameraPosition.X*4.0,CameraPosition.Y*4.0,CameraPosition.Z*4.0); const FStandaloneDesiredTileSet Desired=StandaloneWorldMesher::BuildDesiredSet(World,CameraVoxels); std::vector Tiles;Tiles.reserve(static_cast(TileCount)); for(const FVoxelTileKey& Tile:Desired.Tiles) if(Tile.Level==0&&static_cast(Tiles.size()) Densities; std::vector Surface; }; std::vector Legacy(Tiles.size()); std::vector Detailed(Tiles.size()); UVoxelMarchingCubesMesher Mesher; Mesher.SetGenerator(World.Generator.get());Mesher.bGenerateSkirts=World.bGenerateSkirts; Mesher.SkirtCells=static_cast(World.SkirtCells);Mesher.LODOctaveDrop=World.LODOctaveDrop; int32 MinChunkZ=MIN_int32,MaxChunkZ=MAX_int32,TopChunkZ=0,BottomChunkZ=0; if(World.Settings->bClampViewToStrate&&World.Manager->GetStrateChunkZBounds( StandaloneWorldMesher::CameraChunk(CameraVoxels).Z,TopChunkZ,BottomChunkZ)) { MinChunkZ=BottomChunkZ*CHUNK_SIZE; MaxChunkZ=(TopChunkZ+1)*CHUNK_SIZE; } uint64 TotalSamples=0,ChangedSigns=0; uint64 LegacyHash=14695981039346656037ull,DetailedHash=14695981039346656037ull; const bool PreviousRoundTunnels=World.Generator->bStandaloneResearchRoundTunnels; const bool PreviousEnhancedWalls=World.Generator->bStandaloneResearchEnhancedWalls; const auto Evaluate=[&](bool bEnhanced,std::vector& Out) { World.Generator->bStandaloneResearchRoundTunnels=true; World.Generator->bStandaloneResearchEnhancedWalls=bEnhanced; for(size_t I=0;I(Mesh.Vertices.Num())); for(const FVector& P:Mesh.Vertices) Out[I].Surface.push_back({P.X*0.01,P.Y*0.01,P.Z*0.01}); } }; Evaluate(false,Legacy); Evaluate(true,Detailed); World.Generator->bStandaloneResearchRoundTunnels=PreviousRoundTunnels; World.Generator->bStandaloneResearchEnhancedWalls=PreviousEnhancedWalls; FDirectedSurfaceDistance LegacyToDetailed,DetailedToLegacy; std::vector AllLegacySurface,AllDetailedSurface; for(size_t TileIndex=0;TileIndex(A.Densities[I]);LegacyHash*=1099511628211ull; DetailedHash^=std::bit_cast(B.Densities[I]);DetailedHash*=1099511628211ull; } AllLegacySurface.insert(AllLegacySurface.end(),A.Surface.begin(),A.Surface.end()); AllDetailedSurface.insert(AllDetailedSurface.end(),B.Surface.begin(),B.Surface.end()); } LegacyToDetailed=DirectedSurfaceDistance(AllLegacySurface,AllDetailedSurface); DetailedToLegacy=DirectedSurfaceDistance(AllDetailedSurface,AllLegacySurface); const uint64 DistanceSamples=LegacyToDetailed.Count+DetailedToLegacy.Count; const double MeanDistance=DistanceSamples>0 ?(LegacyToDetailed.Sum+DetailedToLegacy.Sum)/static_cast(DistanceSamples):0.0; const double Hausdorff=std::max(LegacyToDetailed.Maximum,DetailedToLegacy.Maximum); std::printf("[RoundTunnelCompare] tiles=%zu lattice_samples=%llu changed_signs=%llu changed_share=%.6f%% legacy_density_hash=0x%016llx detailed_density_hash=0x%016llx old_vertices=%zu new_vertices=%zu symmetric_vertex_mean_m=%.4f symmetric_vertex_max_m=%.4f unmatched_vertices=%llu\n", Tiles.size(),static_cast(TotalSamples), static_cast(ChangedSigns),TotalSamples?100.0*ChangedSigns/TotalSamples:0.0, static_cast(LegacyHash),static_cast(DetailedHash), AllLegacySurface.size(),AllDetailedSurface.size(),MeanDistance,Hausdorff, static_cast(LegacyToDetailed.Unmatched+DetailedToLegacy.Unmatched)); return TotalSamples>0&&LegacyToDetailed.Unmatched+DetailedToLegacy.Unmatched==0?0:10; } void HashWord(uint64& Hash,uint64 Word,int32 Bytes=8) { for(int32 I=0;I(Word>>(I*8)); Hash*=1099511628211ull; } } struct FHashedTile { FVoxelTileKey Key; uint64 Hash=14695981039346656037ull; }; bool TileKeyLessForHash(const FVoxelTileKey& A,const FVoxelTileKey& B) { if(A.Level!=B.Level)return A.Level& Rows) { std::sort(Rows.begin(),Rows.end(),[](const FHashedTile& A,const FHashedTile& B) {return TileKeyLessForHash(A.Key,B.Key);}); uint64 Hash=14695981039346656037ull; for(const FHashedTile& Row:Rows) { HashWord(Hash,static_cast(Row.Key.Level),4); HashWord(Hash,static_cast(Row.Key.Coord.X),4); HashWord(Hash,static_cast(Row.Key.Coord.Y),4); HashWord(Hash,static_cast(Row.Key.Coord.Z),4); HashWord(Hash,Row.Hash); } return Hash; } int RunPipelinedStreamingBenchmark(std::shared_ptr OwnerWorld, const VoxelForgeCore::ResolvedWorldSnapshot& CoreSnapshot, const FVector& CameraPositionVoxels,int32 WorkerCount,int32 MaxLevel, VoxelForgeCore::DetailVariant DetailVariant,const VoxelForgeCore::JobScheduler& Scheduler, bool bHashDensity,bool bSkipUvAndColors,bool bSkipMaterialGroups,bool bSkipUV,bool bSkipColors, std::chrono::steady_clock::time_point ColdStart) { using Clock=std::chrono::steady_clock; FStandaloneOwnerWorld& World=*OwnerWorld; const bool bRoundTunnels=World.Generator->bStandaloneResearchRoundTunnels; const bool bEnhancedTunnelWalls=World.Generator->bStandaloneResearchEnhancedWalls; VoxelForgeCore::World Shape(CoreSnapshot); FStandaloneDesiredTileSet Desired=StandaloneWorldMesher::BuildDesiredSet(World,CameraPositionVoxels); const auto CoreTiles=Shape.desiredTiles( {CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z}); Desired.Tiles.clear();Desired.Tiles.reserve(CoreTiles.size()); for(const auto& Key:CoreTiles) Desired.Tiles.emplace_back(FIntVector(Key.coordinate.x,Key.coordinate.y,Key.coordinate.z),Key.lod); if(MaxLevel>=0) Desired.Tiles.erase(std::remove_if(Desired.Tiles.begin(),Desired.Tiles.end(), [&](const FVoxelTileKey& Tile){return Tile.Level>MaxLevel;}),Desired.Tiles.end()); FIntVector FineMin(INT32_MAX,INT32_MAX,INT32_MAX),FineMax(INT32_MIN,INT32_MIN,INT32_MIN); FIntVector ClipMin(INT32_MAX,INT32_MAX,INT32_MAX),ClipMax(INT32_MIN,INT32_MIN,INT32_MIN); for(const FVoxelTileKey& Tile:Desired.Tiles) { const FIntVector Origin=Tile.OriginVoxels();const int32 Extent=Tile.ExtentVoxels(); ClipMin.X=std::min(ClipMin.X,Origin.X);ClipMin.Y=std::min(ClipMin.Y,Origin.Y);ClipMin.Z=std::min(ClipMin.Z,Origin.Z); ClipMax.X=std::max(ClipMax.X,Origin.X+Extent);ClipMax.Y=std::max(ClipMax.Y,Origin.Y+Extent);ClipMax.Z=std::max(ClipMax.Z,Origin.Z+Extent); if(Tile.Level Neighborhood; Neighborhood.reserve(32); for(const FVoxelTileKey& Tile:Desired.Tiles) if(Tile.Level==0&&std::abs(Tile.Coord.X-CenterChunk.X)<=1 &&std::abs(Tile.Coord.Y-CenterChunk.Y)<=1&&std::abs(Tile.Coord.Z-CenterChunk.Z)<=1) Neighborhood.insert(Tile); if(Neighborhood.size()!=27) {std::fprintf(stderr,"[StreamPipeline] expected 27 player-neighborhood tiles, found %zu.\n",Neighborhood.size());return 7;} // The initial desired set now owns all clipmap metadata needed by this Core-only run. // Release the separate compatibility-world generation graph before compiling Core. World.Generator.reset(); World.Manager.reset(); World.DefinitionStorage.clear(); World.BiomeStorage.clear(); World.OperationStorage.clear(); World.DensitySamples.clear(); std::string BuildError; const bool bIncludeFarWorld=MaxLevel<0||MaxLevel>=World.FullResClipLevels; const auto ShapeBuildStart=Clock::now(); VoxelForgeCore::ShapeBuildRequest ShapeRequest; ShapeRequest.minVoxel={FineMin.X,FineMin.Y,FineMin.Z}; ShapeRequest.maxVoxel={FineMax.X,FineMax.Y,FineMax.Z}; ShapeRequest.clipMinVoxel={ClipMin.X,ClipMin.Y,ClipMin.Z}; ShapeRequest.clipMaxVoxel={ClipMax.X,ClipMax.Y,ClipMax.Z}; ShapeRequest.workerLimit=static_cast(std::clamp(WorkerCount,1,16)); ShapeRequest.detail=DetailVariant;ShapeRequest.includeFarWorld=bIncludeFarWorld; ShapeRequest.roundTunnels=bRoundTunnels; ShapeRequest.enhancedTunnelWalls=bEnhancedTunnelWalls; if(!Shape.compile(ShapeRequest,Scheduler,BuildError)) {std::fprintf(stderr,"[StreamPipeline] full shape build failed: %s\n",BuildError.c_str());return 2;} const auto ShapeReady=Clock::now(); const double ShapeSeconds=std::chrono::duration(ShapeReady-ShapeBuildStart).count(); FStandaloneStreamingGenerator Streamer(World,WorkerCount,bHashDensity,nullptr,MaxLevel, bSkipUvAndColors,bSkipMaterialGroups,bSkipUV,bSkipColors,&Shape); const auto StreamStart=Clock::now(); const FStandaloneStreamingUpdate Update=Streamer.StartWithDesired(Desired); if(Update.DesiredTiles!=static_cast(Desired.Tiles.size())) { Streamer.Stop(); std::fprintf(stderr,"[StreamPipeline] expected %zu tiles but queued %d.\n", Desired.Tiles.size(),Update.DesiredTiles);return 7; } std::vector DensityRows,MeshRows,PayloadRows,TopologyRows; int32 Finished=0,NeighborhoodFinished=0,FullDetailFinished=0; int32 FullDetailExpected=0; uint64 NativeSolidBoxes=0,NativeAirBoxes=0,NativeMixedBoxes=0,NativeUnknownBoxes=0; uint64 NativeFieldCalls=0,NativeColumnHits=0,NativeColumnMisses=0,NativeMeshingSkips=0; double NativeClassificationMilliseconds=0.0,NativeColumnComputeMilliseconds=0.0; double NativeMeshingMilliseconds=0.0; for(const FVoxelTileKey& Tile:Desired.Tiles) if(Tile.Level Ready=Streamer.TakeReady(); if(Ready.empty()){std::this_thread::sleep_for(std::chrono::milliseconds(1));continue;} for(const FStandaloneCpuTile& Tile:Ready) { ++Finished; WholeViewReady=std::max(WholeViewReady,Tile.CompletedAt); if(Neighborhood.contains(Tile.Key)) { ++NeighborhoodFinished; NeighborhoodReady=std::max(NeighborhoodReady,Tile.CompletedAt); } if(Tile.Key.Level(Neighborhood.size())) { std::printf("[PipelineMilestone] neighborhood_ready=%.3fs generated=%d/27\n", std::chrono::duration(NeighborhoodReady-ColdStart).count(),NeighborhoodFinished); bNeighborhoodReported=true; } if(!bFullDetailReported&&FullDetailFinished==FullDetailExpected) { std::printf("[PipelineMilestone] full_detail_ready=%.3fs generated=%d/%d\n", std::chrono::duration(FullDetailReady-ColdStart).count(), FullDetailFinished,FullDetailExpected); bFullDetailReported=true; } } Streamer.Stop(); const double NeighborhoodSeconds=std::chrono::duration(NeighborhoodReady-ColdStart).count(); const double NeighborhoodMeshSeconds=std::chrono::duration(NeighborhoodReady-ShapeReady).count(); const double FullDetailSeconds=std::chrono::duration(FullDetailReady-ColdStart).count(); const double WholeViewSeconds=std::chrono::duration(WholeViewReady-ColdStart).count(); const double StreamSeconds=std::chrono::duration(WholeViewReady-StreamStart).count(); std::printf("[StreamPipeline] workers=%d shape=%.3fs neighborhood_mesh=%.3fs neighborhood_ready=%.3fs full_detail_ready=%.3fs whole_view_ready=%.3fs neighborhood_tiles=%d/27 full_detail_tiles=%d/%d whole_tiles=%d/%zu stream_wall=%.3fs cache_hits=0 full_payload=1\n", WorkerCount,ShapeSeconds,NeighborhoodMeshSeconds,NeighborhoodSeconds, FullDetailSeconds,WholeViewSeconds,NeighborhoodFinished, FullDetailFinished,FullDetailExpected,Finished,Desired.Tiles.size(),StreamSeconds); std::printf("[WorldAssemblerTilePipeline] full_detail_tiles=%d solid_boxes=%llu air_boxes=%llu mixed_boxes=%llu unknown_boxes=%llu whole_tile_skips=%llu field_calls=%llu column_cache_hits=%llu column_cache_misses=%llu column_compute_worker_ms=%.3f classification_worker_ms=%.3f meshing_worker_ms=%.3f\n", FullDetailExpected,static_cast(NativeSolidBoxes), static_cast(NativeAirBoxes), static_cast(NativeMixedBoxes), static_cast(NativeUnknownBoxes), static_cast(NativeMeshingSkips), static_cast(NativeFieldCalls), static_cast(NativeColumnHits), static_cast(NativeColumnMisses), NativeColumnComputeMilliseconds,NativeClassificationMilliseconds, NativeMeshingMilliseconds); bool bHashesPassing=true; if(bHashDensity) { bHashesPassing=DensityRows.size()==Desired.Tiles.size() &&MeshRows.size()==Desired.Tiles.size() &&PayloadRows.size()==Desired.Tiles.size() &&TopologyRows.size()==Desired.Tiles.size(); std::vector FullDensity,FullMesh,FullPayload,FullTopology; for(const FHashedTile& Row:DensityRows)if(Row.Key.Level(HashTileRows(FullDensity)), static_cast(HashTileRows(FullMesh)), static_cast(HashTileRows(FullPayload)), static_cast(HashTileRows(FullTopology))); std::printf("[PipelineWholeViewHash] tiles=%zu density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx\n", Desired.Tiles.size(),static_cast(HashTileRows(DensityRows)), static_cast(HashTileRows(MeshRows)), static_cast(HashTileRows(PayloadRows)), static_cast(HashTileRows(TopologyRows))); } return NeighborhoodFinished==static_cast(Neighborhood.size()) &&FullDetailFinished==FullDetailExpected&&Finished==Update.DesiredTiles&&bHashesPassing?0:6; } int RunStreamingBenchmark(FStandaloneOwnerWorld& World,VoxelForgeCore::World* CoreWorld, const FVector& CameraPositionVoxels, int32 WorkerCount,int32 MaxLevel,bool bRoundTunnels, bool bEnhancedWalls,const FStandaloneMeshCache* Cache, bool bHashDensity,bool bSkipUvAndColors,bool bSkipMaterialGroups, bool bSkipUV,bool bSkipColors, bool bShardAudit,bool bFarSurvivalAudit,bool bFarAuditBadShell, float CameraYaw,float CameraPitch, const std::string& BakeCachePath, const FStandaloneMeshCacheMetadata& CacheMetadata) { FStandaloneDesiredTileSet Desired=StandaloneWorldMesher::BuildDesiredSet(World,CameraPositionVoxels); if(CoreWorld) { const auto CoreTiles=CoreWorld->desiredTiles( {CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z}); Desired.Tiles.clear();Desired.Tiles.reserve(CoreTiles.size()); for(const auto& Key:CoreTiles) Desired.Tiles.emplace_back(FIntVector(Key.coordinate.x,Key.coordinate.y,Key.coordinate.z),Key.lod); } if(MaxLevel>=0) Desired.Tiles.erase(std::remove_if(Desired.Tiles.begin(),Desired.Tiles.end(), [&](const FVoxelTileKey& Tile){return Tile.Level>MaxLevel;}),Desired.Tiles.end()); std::unordered_set DesiredTileSet; DesiredTileSet.reserve(Desired.Tiles.size()*2+1); for(const FVoxelTileKey& Tile:Desired.Tiles)DesiredTileSet.insert(Tile); if(Desired.Tiles.size()>1000000) { std::fprintf(stderr,"Stream benchmark rejected an unsafe desired set of %zu tiles.\n", Desired.Tiles.size()); return 7; } const int32 FullDetailExpected=static_cast(std::count_if( Desired.Tiles.begin(),Desired.Tiles.end(),[&](const FVoxelTileKey& Tile) {return Tile.Level FarAudit; if(bFarSurvivalAudit) { if(!CoreWorld||!CoreWorld->hasFarWorld()) {std::fprintf(stderr,"Far survival audit requires a compiled core world with far-parent data.\n");return 15;} FarAudit=std::make_unique(World,*CoreWorld,Desired.Tiles,bFarAuditBadShell); } std::array,MaxLevels+1> HashRows; std::array,MaxLevels+1> MeshHashRows; std::array,MaxLevels+1> PayloadHashRows; std::array,MaxLevels+1> TopologyHashRows; std::array SamplesByLevel{}; std::array VerticesByLevel{}; std::array IndicesByLevel{}; std::array TilesByLevel{}; std::array WorkerSecondsByLevel{}; std::array FirstCompletionByLevel{}; std::array LastCompletionByLevel{}; std::array OutputBytesByLevel{}; std::array MeshPayloadAllocatedBytesByLevel{}; FirstCompletionByLevel.fill(std::numeric_limits::infinity()); std::unordered_set PlayerNeighborhoodTiles; for(const FVoxelTileKey& Tile:Desired.Tiles) if(Tile.Level==0&&std::abs(Tile.Coord.X-Desired.CenterChunk.X)<=1 &&std::abs(Tile.Coord.Y-Desired.CenterChunk.Y)<=1 &&std::abs(Tile.Coord.Z-Desired.CenterChunk.Z)<=1) PlayerNeighborhoodTiles.insert(Tile); std::unordered_set PlayerNeighborhoodReady; auto PlayerNeighborhoodCompleted=std::chrono::steady_clock::time_point{}; std::vector CacheTiles; if(!BakeCachePath.empty())CacheTiles.reserve(Desired.Tiles.size()); uint64 NativeSolidBoxes=0,NativeAirBoxes=0,NativeMixedBoxes=0,NativeUnknownBoxes=0; uint64 NativeFieldCalls=0,NativeColumnHits=0,NativeColumnMisses=0,NativeMeshingSkips=0; uint64 NativeFloatFieldCalls=0,NativeLatticeFieldCalls=0,NativeUnclampedFieldCalls=0; double NativeClassificationMilliseconds=0.0,NativeColumnComputeMilliseconds=0.0; double NativeMeshingMilliseconds=0.0; uint64 WholeSolidBoxes=0,WholeAirBoxes=0,WholeMixedBoxes=0,WholeUnknownBoxes=0; uint64 WholeFieldCalls=0,WholeColumnHits=0,WholeColumnMisses=0,WholeTileSkips=0; uint64 WholeFloatFieldCalls=0,WholeLatticeFieldCalls=0,WholeUnclampedFieldCalls=0; double WholeClassificationMilliseconds=0.0,WholeColumnComputeMilliseconds=0.0; double WholeMeshingMilliseconds=0.0; uint64 WholeCapRefinedTiles=0,WholeCapRefinedCells=0,WholeCapRefinedTriangles=0; int32 WholeCapTileCoordMin[3]={INT32_MAX,INT32_MAX,INT32_MAX}; int32 WholeCapTileCoordMax[3]={INT32_MIN,INT32_MIN,INT32_MIN}; uint64 WholeSolidBoxesByLevel[MaxLevels+1]{},WholeAirBoxesByLevel[MaxLevels+1]{}; uint64 WholeMixedBoxesByLevel[MaxLevels+1]{},WholeUnknownBoxesByLevel[MaxLevels+1]{}; uint64 WholeFieldCallsByLevel[MaxLevels+1]{},WholeColumnHitsByLevel[MaxLevels+1]{}; uint64 WholeFloatFieldCallsByLevel[MaxLevels+1]{},WholeLatticeFieldCallsByLevel[MaxLevels+1]{}; uint64 WholeUnclampedFieldCallsByLevel[MaxLevels+1]{}; uint64 WholeColumnMissesByLevel[MaxLevels+1]{},WholeTileSkipsByLevel[MaxLevels+1]{}; double WholeClassificationMillisecondsByLevel[MaxLevels+1]{}; double WholeColumnComputeMillisecondsByLevel[MaxLevels+1]{}; double WholeMeshingMillisecondsByLevel[MaxLevels+1]{}; if(CoreWorld&&!FarAudit) { // Tile keys and band limits are already captured in Desired. Core owns field and // mesh generation, so discard the unused compatibility generator before streaming. World.Generator.reset(); World.Manager.reset(); World.DefinitionStorage.clear(); World.BiomeStorage.clear(); World.OperationStorage.clear(); World.DensitySamples.clear(); } const auto Start=std::chrono::steady_clock::now(); FStandaloneStreamingGenerator Streamer(World,WorkerCount, bHashDensity||!BakeCachePath.empty(),Cache,MaxLevel, bSkipUvAndColors,bSkipMaterialGroups,bSkipUV,bSkipColors,CoreWorld); const FStandaloneStreamingUpdate Update=CoreWorld ?Streamer.StartWithDesired(Desired):Streamer.Start(CameraPositionVoxels); const double LOD0Width=static_cast(2*World.ClipRadius+2) *CHUNK_SIZE*VOXEL_SIZE/100.0; std::printf("[StreamBenchmarkConfig] clip_radius=%d lod0_cube=%.0fm voxel=25cm fullres_levels=%d max_level_filter=%d workers=%d full_detail_tiles=%d desired_tiles=%d variant=%s uv=%s colors=%s material_groups=%s hash=%s\n", World.ClipRadius,LOD0Width,World.FullResClipLevels,MaxLevel<0?World.MaxClipLevel:MaxLevel, Streamer.GetWorkerCount(),FullDetailExpected,Update.DesiredTiles, bRoundTunnels?(bEnhancedWalls?"round-detailed":"round-legacy"):"base", (bSkipUvAndColors||bSkipUV)?"skipped":"full", (bSkipUvAndColors||bSkipColors)?"skipped":"full", bSkipMaterialGroups?"skipped":"full", (bHashDensity||!BakeCachePath.empty())?"on":"off"); std::fflush(stdout); int32 Finished=0,FullDetailFinished=0; bool bFullDetailTimeReported=false; double FullDetailSeconds=0.0; const int32 DesiredTotal=Update.DesiredTiles; FMeshSheetAudit MeshSheetStats; FMeshArtifactAudit MeshArtifactStats; FCoarsePanelAudit CoarsePanelStats; uint64 MeshAuditedTiles=0; while(Finished Ready=Streamer.TakeReady(); if(Ready.empty()) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; } for(FStandaloneCpuTile& Tile:Ready) { if(FarAudit)FarAudit->AuditTile(Tile); ++Finished; const int32 Level=Tile.Key.Level; if(CoreWorld) { WholeSolidBoxes+=Tile.CoreDiagnostics.solidBoxes; WholeAirBoxes+=Tile.CoreDiagnostics.airBoxes; WholeMixedBoxes+=Tile.CoreDiagnostics.mixedBoxes; WholeUnknownBoxes+=Tile.CoreDiagnostics.unknownBoxes; WholeFieldCalls+=Tile.CoreDiagnostics.fieldCalls; WholeFloatFieldCalls+=Tile.CoreDiagnostics.floatFieldCalls; WholeLatticeFieldCalls+=Tile.CoreDiagnostics.latticeFieldCalls; WholeUnclampedFieldCalls+=Tile.CoreDiagnostics.unclampedFieldCalls; WholeColumnHits+=Tile.CoreDiagnostics.columnCacheHits; WholeColumnMisses+=Tile.CoreDiagnostics.columnCacheMisses; WholeTileSkips+=Tile.CoreDiagnostics.meshingSkipped?1u:0u; WholeCapRefinedTiles+=Tile.CoreDiagnostics.capRefined?1u:0u; WholeCapRefinedCells+=Tile.CoreDiagnostics.capRefinedCells; WholeCapRefinedTriangles+=Tile.CoreDiagnostics.capRefinedTriangles; if(Tile.CoreDiagnostics.capRefined) for(int32 Axis=0;Axis<3;++Axis) { WholeCapTileCoordMin[Axis]=std::min(WholeCapTileCoordMin[Axis], (&Tile.Key.Coord.X)[Axis]); WholeCapTileCoordMax[Axis]=std::max(WholeCapTileCoordMax[Axis], (&Tile.Key.Coord.X)[Axis]); } WholeClassificationMilliseconds+=Tile.CoreDiagnostics.classificationMilliseconds; WholeColumnComputeMilliseconds+=Tile.CoreDiagnostics.columnComputeMilliseconds; WholeMeshingMilliseconds+=Tile.CoreDiagnostics.meshingMilliseconds; if(Level>=0&&Level<=MaxLevels) { WholeSolidBoxesByLevel[Level]+=Tile.CoreDiagnostics.solidBoxes; WholeAirBoxesByLevel[Level]+=Tile.CoreDiagnostics.airBoxes; WholeMixedBoxesByLevel[Level]+=Tile.CoreDiagnostics.mixedBoxes; WholeUnknownBoxesByLevel[Level]+=Tile.CoreDiagnostics.unknownBoxes; WholeFieldCallsByLevel[Level]+=Tile.CoreDiagnostics.fieldCalls; WholeFloatFieldCallsByLevel[Level]+=Tile.CoreDiagnostics.floatFieldCalls; WholeLatticeFieldCallsByLevel[Level]+=Tile.CoreDiagnostics.latticeFieldCalls; WholeUnclampedFieldCallsByLevel[Level]+=Tile.CoreDiagnostics.unclampedFieldCalls; WholeColumnHitsByLevel[Level]+=Tile.CoreDiagnostics.columnCacheHits; WholeColumnMissesByLevel[Level]+=Tile.CoreDiagnostics.columnCacheMisses; WholeTileSkipsByLevel[Level]+=Tile.CoreDiagnostics.meshingSkipped?1u:0u; WholeClassificationMillisecondsByLevel[Level] +=Tile.CoreDiagnostics.classificationMilliseconds; WholeColumnComputeMillisecondsByLevel[Level] +=Tile.CoreDiagnostics.columnComputeMilliseconds; WholeMeshingMillisecondsByLevel[Level] +=Tile.CoreDiagnostics.meshingMilliseconds; } } if(PlayerNeighborhoodTiles.contains(Tile.Key)) { PlayerNeighborhoodReady.insert(Tile.Key); if(PlayerNeighborhoodReady.size()==PlayerNeighborhoodTiles.size()) PlayerNeighborhoodCompleted=Tile.CompletedAt; } if(Level>=0&&Level<=MaxLevels) { SamplesByLevel[Level]+=Tile.DensitySamples; VerticesByLevel[Level]+=Tile.Vertices.size(); IndicesByLevel[Level]+=Tile.Indices.size(); ++TilesByLevel[Level]; WorkerSecondsByLevel[Level]+=Tile.WorkerSeconds; const double CompletedSeconds=std::chrono::duration(Tile.CompletedAt-Start).count(); FirstCompletionByLevel[Level]=std::min(FirstCompletionByLevel[Level],CompletedSeconds); LastCompletionByLevel[Level]=std::max(LastCompletionByLevel[Level],CompletedSeconds); OutputBytesByLevel[Level]+=static_cast(Tile.Vertices.capacity())*sizeof(FStandaloneCpuVertex) +static_cast(Tile.Indices.capacity())*sizeof(uint32) +static_cast(Tile.TriangleSkirtFaceMasks.capacity())*sizeof(uint8); MeshPayloadAllocatedBytesByLevel[Level]+=Tile.MeshPayloadAllocatedBytes; if(Tile.bHasDensityHash)HashRows[Level].push_back({Tile.Key,Tile.DensityHash}); if(Tile.bHasMeshHash)MeshHashRows[Level].push_back({Tile.Key,Tile.MeshHash}); if(Tile.bHasPayloadHash)PayloadHashRows[Level].push_back({Tile.Key,Tile.PayloadHash}); if(Tile.bHasTopologyHash)TopologyHashRows[Level].push_back({Tile.Key,Tile.TopologyHash}); } if(LevelMeshArtifactStats.MaximumAnalyticEdgeShiftVoxels) { MeshArtifactStats.MaximumAnalyticEdgeShiftVoxels=TileAudit.MaximumAnalyticEdgeShiftVoxels; MeshArtifactStats.WorstShiftPosition=TileAudit.WorstShiftPosition; MeshArtifactStats.WorstShiftFraction=TileAudit.WorstShiftFraction; MeshArtifactStats.WorstShiftD0=TileAudit.WorstShiftD0; MeshArtifactStats.WorstShiftD1=TileAudit.WorstShiftD1; MeshArtifactStats.WorstShiftExactD0=TileAudit.WorstShiftExactD0; MeshArtifactStats.WorstShiftExactD1=TileAudit.WorstShiftExactD1; MeshArtifactStats.WorstShiftAxis=TileAudit.WorstShiftAxis; } if(TileAudit.MaximumAbsSourceResidual>MeshArtifactStats.MaximumAbsSourceResidual) { MeshArtifactStats.MaximumAbsSourceResidual=TileAudit.MaximumAbsSourceResidual; MeshArtifactStats.WorstResidualPosition=TileAudit.WorstResidualPosition; } MeshArtifactStats.SumNormalAgreement+=TileAudit.SumNormalAgreement; MeshArtifactStats.MinimumNormalAgreement=std::min( MeshArtifactStats.MinimumNormalAgreement,TileAudit.MinimumNormalAgreement); MeshArtifactStats.MaximumAirSkirtDensity=std::max( MeshArtifactStats.MaximumAirSkirtDensity,TileAudit.MaximumAirSkirtDensity); MeshArtifactStats.MaximumPatchDominance=std::max( MeshArtifactStats.MaximumPatchDominance,TileAudit.MaximumPatchDominance); for(size_t Bin=0;Bin=1&&CoreWorld) { const FCoarsePanelAudit TileAudit=AuditCoarseSurfacePanels( Tile,*CoreWorld,CoreWorld->configuration(),CoarsePanelStats.OffSurfacePanels<8); CoarsePanelStats.Tiles+=TileAudit.Tiles; CoarsePanelStats.PlanarOpenComponents+=TileAudit.PlanarOpenComponents; CoarsePanelStats.OffSurfacePanels+=TileAudit.OffSurfacePanels; CoarsePanelStats.Triangles+=TileAudit.Triangles; CoarsePanelStats.MaximumSourceErrorVoxels=std::max( CoarsePanelStats.MaximumSourceErrorVoxels,TileAudit.MaximumSourceErrorVoxels); } if(!BakeCachePath.empty())CacheTiles.push_back(std::move(Tile)); } if(!bFullDetailTimeReported&&FullDetailFinished>=FullDetailExpected) { bFullDetailTimeReported=true; FullDetailSeconds=std::chrono::duration( std::chrono::steady_clock::now()-Start).count(); std::vector FullRows; std::vector FullMeshRows; std::vector FullPayloadRows; std::vector FullTopologyRows; for(int32 Level=0;Level(HashTileRows(FullRows)), static_cast(HashTileRows(FullMeshRows)), static_cast(HashTileRows(FullPayloadRows)), static_cast(HashTileRows(FullTopologyRows))); else std::printf("[StreamFullDetail] wall=%.3fs generated=%d/%d resident_tiles_cpu_only=1 hash=off\n", FullDetailSeconds,FullDetailFinished,FullDetailExpected); if(CoreWorld) std::printf("[WorldAssemblerTilePipeline] full_detail_tiles=%d solid_boxes=%llu air_boxes=%llu mixed_boxes=%llu unknown_boxes=%llu whole_tile_skips=%llu field_calls=%llu float_field_calls=%llu lattice_field_calls=%llu unclamped_field_calls=%llu column_cache_hits=%llu column_cache_misses=%llu column_compute_worker_ms=%.3f classification_worker_ms=%.3f meshing_worker_ms=%.3f\n", FullDetailExpected,static_cast(NativeSolidBoxes), static_cast(NativeAirBoxes), static_cast(NativeMixedBoxes), static_cast(NativeUnknownBoxes), static_cast(NativeMeshingSkips), static_cast(NativeFieldCalls), static_cast(NativeFloatFieldCalls), static_cast(NativeLatticeFieldCalls), static_cast(NativeUnclampedFieldCalls), static_cast(NativeColumnHits), static_cast(NativeColumnMisses), NativeColumnComputeMilliseconds,NativeClassificationMilliseconds, NativeMeshingMilliseconds); std::fflush(stdout); } } const double FullClipSeconds=std::chrono::duration( std::chrono::steady_clock::now()-Start).count(); if(!PlayerNeighborhoodTiles.empty()&&PlayerNeighborhoodReady.size()==PlayerNeighborhoodTiles.size()) std::printf("[PlayerNeighborhood] lod0_tiles=%zu/%zu mesh_ready=%.3fs collision_cook=unavailable_in_standalone\n", PlayerNeighborhoodReady.size(),PlayerNeighborhoodTiles.size(), std::chrono::duration(PlayerNeighborhoodCompleted-Start).count()); else std::printf("[PlayerNeighborhood] lod0_tiles=%zu/%zu mesh_ready=missing collision_cook=unavailable_in_standalone\n", PlayerNeighborhoodReady.size(),PlayerNeighborhoodTiles.size()); const double TotalWorkerSeconds=std::accumulate(WorkerSecondsByLevel.begin(),WorkerSecondsByLevel.end(),0.0); const uint64 TotalMeshPayloadAllocatedBytes=std::accumulate( MeshPayloadAllocatedBytesByLevel.begin(),MeshPayloadAllocatedBytesByLevel.end(),uint64{0}); const uint64 TotalViewerOutputBytes=std::accumulate( OutputBytesByLevel.begin(),OutputBytesByLevel.end(),uint64{0}); const double WorkerBusyPercent=100.0*TotalWorkerSeconds /(std::max(1,WorkerCount)*std::max(0.001,FullClipSeconds)); std::vector AllRows; std::vector AllMeshRows; std::vector AllPayloadRows; std::vector AllTopologyRows; if(bHashDensity||!BakeCachePath.empty()) for(int32 Level=0;Level<=MaxLevels;++Level) { AllRows.insert(AllRows.end(),HashRows[Level].begin(),HashRows[Level].end()); AllMeshRows.insert(AllMeshRows.end(),MeshHashRows[Level].begin(),MeshHashRows[Level].end()); AllPayloadRows.insert(AllPayloadRows.end(),PayloadHashRows[Level].begin(),PayloadHashRows[Level].end()); AllTopologyRows.insert(AllTopologyRows.end(),TopologyHashRows[Level].begin(),TopologyHashRows[Level].end()); } if(bHashDensity||!BakeCachePath.empty()) std::printf("[StreamFullClipmap] wall=%.3fs generated=%d/%d worker_sum=%.3fs worker_busy=%.1f%% worker_idle=%.1f%% payload_alloc=%.2fMiB viewer_output=%.2fMiB tiles=%d density_hash=0x%016llx mesh_hash=0x%016llx payload_hash=0x%016llx topology_hash=0x%016llx\n", FullClipSeconds,Finished,DesiredTotal,TotalWorkerSeconds,WorkerBusyPercent, std::max(0.0,100.0-WorkerBusyPercent), static_cast(TotalMeshPayloadAllocatedBytes)/1048576.0, static_cast(TotalViewerOutputBytes)/1048576.0, DesiredTotal,static_cast(HashTileRows(AllRows)), static_cast(HashTileRows(AllMeshRows)), static_cast(HashTileRows(AllPayloadRows)), static_cast(HashTileRows(AllTopologyRows))); else std::printf("[StreamFullClipmap] wall=%.3fs generated=%d/%d worker_sum=%.3fs worker_busy=%.1f%% worker_idle=%.1f%% payload_alloc=%.2fMiB viewer_output=%.2fMiB tiles=%d hash=off\n", FullClipSeconds,Finished,DesiredTotal,TotalWorkerSeconds,WorkerBusyPercent, std::max(0.0,100.0-WorkerBusyPercent), static_cast(TotalMeshPayloadAllocatedBytes)/1048576.0, static_cast(TotalViewerOutputBytes)/1048576.0,DesiredTotal); if(CoreWorld) std::printf("[WorldAssemblerWholeViewPipeline] tiles=%d solid_boxes=%llu air_boxes=%llu mixed_boxes=%llu unknown_boxes=%llu whole_tile_skips=%llu field_calls=%llu float_field_calls=%llu lattice_field_calls=%llu unclamped_field_calls=%llu column_cache_hits=%llu column_cache_misses=%llu column_compute_worker_ms=%.3f classification_worker_ms=%.3f meshing_worker_ms=%.3f\n", DesiredTotal,static_cast(WholeSolidBoxes), static_cast(WholeAirBoxes), static_cast(WholeMixedBoxes), static_cast(WholeUnknownBoxes), static_cast(WholeTileSkips), static_cast(WholeFieldCalls), static_cast(WholeFloatFieldCalls), static_cast(WholeLatticeFieldCalls), static_cast(WholeUnclampedFieldCalls), static_cast(WholeColumnHits), static_cast(WholeColumnMisses), WholeColumnComputeMilliseconds,WholeClassificationMilliseconds, WholeMeshingMilliseconds); if(CoreWorld) std::printf("[WorldAssemblerLod8Cap] grid_step_voxels=128 refined_tiles=%llu valid_grid_cells=%llu generated_triangles=%llu\n", static_cast(WholeCapRefinedTiles), static_cast(WholeCapRefinedCells), static_cast(WholeCapRefinedTriangles)); if(CoreWorld&&WholeCapRefinedTiles>0) std::printf("[WorldAssemblerLod8CapTiles] lod=8 extent_voxels=8192 coord_min=(%d,%d,%d) coord_max=(%d,%d,%d)\n", WholeCapTileCoordMin[0],WholeCapTileCoordMin[1],WholeCapTileCoordMin[2], WholeCapTileCoordMax[0],WholeCapTileCoordMax[1],WholeCapTileCoordMax[2]); if(CoreWorld) for(int32 Level=0;Level<=MaxLevels;++Level) if(TilesByLevel[Level]>0) std::printf("[WorldAssemblerLODProfile] lod=%d tiles=%llu solid_boxes=%llu air_boxes=%llu mixed_boxes=%llu unknown_boxes=%llu whole_tile_skips=%llu field_calls=%llu float_field_calls=%llu lattice_field_calls=%llu unclamped_field_calls=%llu column_hits=%llu column_misses=%llu column_compute_worker_ms=%.3f classification_worker_ms=%.3f meshing_worker_ms=%.3f\n", Level,static_cast(TilesByLevel[Level]), static_cast(WholeSolidBoxesByLevel[Level]), static_cast(WholeAirBoxesByLevel[Level]), static_cast(WholeMixedBoxesByLevel[Level]), static_cast(WholeUnknownBoxesByLevel[Level]), static_cast(WholeTileSkipsByLevel[Level]), static_cast(WholeFieldCallsByLevel[Level]), static_cast(WholeFloatFieldCallsByLevel[Level]), static_cast(WholeLatticeFieldCallsByLevel[Level]), static_cast(WholeUnclampedFieldCallsByLevel[Level]), static_cast(WholeColumnHitsByLevel[Level]), static_cast(WholeColumnMissesByLevel[Level]), WholeColumnComputeMillisecondsByLevel[Level], WholeClassificationMillisecondsByLevel[Level], WholeMeshingMillisecondsByLevel[Level]); std::printf("[StreamCacheUse] hits=%llu requested=%d\n", static_cast(Streamer.GetCacheHits()),DesiredTotal); if(bShardAudit) std::printf("[ThinMeshShardAudit] level=0 tiles=%llu view_components=%llu small_components=%llu isolated_in_view_small=%llu boundary_in_view_small=%llu thin_sheets=%llu sheet_triangles=%llu thickness_lt=1.000 vox pca_scale=3.5x_sigma status=%s\n", static_cast(MeshAuditedTiles), static_cast(MeshSheetStats.Components), static_cast(MeshSheetStats.SmallComponents), static_cast(MeshSheetStats.SmallComponentsInView), static_cast(MeshSheetStats.BoundarySmallComponentsInView), static_cast(MeshSheetStats.ThinSheets), static_cast(MeshSheetStats.TrianglesInThinSheets), MeshSheetStats.ThinSheets==0&&MeshSheetStats.SmallComponentsInView==0?"PASS":"FAIL"); if(bShardAudit&&CoreWorld) { const double MidpointShare=MeshArtifactStats.EdgeVertices ?100.0*static_cast(MeshArtifactStats.MidpointVertices) /MeshArtifactStats.EdgeVertices:0.0; const double MeanSourceResidual=MeshArtifactStats.FieldEdgeChecks ?MeshArtifactStats.SumAbsSourceResidual/MeshArtifactStats.FieldEdgeChecks:0.0; const double MeanAnalyticEdgeShift=MeshArtifactStats.FieldEdgeChecks ?MeshArtifactStats.SumAnalyticEdgeShiftVoxels /std::max(1,MeshArtifactStats.FieldEdgeChecks-MeshArtifactStats.AnalyticCrossingMisses):0.0; const double MeanNormalAgreement=MeshArtifactStats.NormalChecks ?MeshArtifactStats.SumNormalAgreement/MeshArtifactStats.NormalChecks:1.0; std::printf("[MeshFieldFitAudit] edge_checks=%llu analytic_crossing_misses=%llu old_int8_range_edges=%llu source_residual_mean=%.4f max=%.4f vox analytic_edge_shift_mean=%.4f max=%.4f vox sampled_normal_dot_mean=%.4f min=%.4f\n", static_cast(MeshArtifactStats.FieldEdgeChecks), static_cast(MeshArtifactStats.AnalyticCrossingMisses), static_cast(MeshArtifactStats.OldInt8RangeEdges), MeanSourceResidual,MeshArtifactStats.MaximumAbsSourceResidual, MeanAnalyticEdgeShift,MeshArtifactStats.MaximumAnalyticEdgeShiftVoxels, MeanNormalAgreement,MeshArtifactStats.MinimumNormalAgreement); std::printf("[MeshFieldFitWorst] shift=%.4f vox vertex=(%.3f,%.3f,%.3f) axis=%d fraction=%.4f packed=(%.4f,%.4f) analytic=(%.4f,%.4f) max_source_residual=%.4f vox vertex=(%.3f,%.3f,%.3f)\n", MeshArtifactStats.MaximumAnalyticEdgeShiftVoxels, MeshArtifactStats.WorstShiftPosition[0],MeshArtifactStats.WorstShiftPosition[1], MeshArtifactStats.WorstShiftPosition[2],MeshArtifactStats.WorstShiftAxis, MeshArtifactStats.WorstShiftFraction,MeshArtifactStats.WorstShiftD0, MeshArtifactStats.WorstShiftD1,MeshArtifactStats.WorstShiftExactD0, MeshArtifactStats.WorstShiftExactD1,MeshArtifactStats.MaximumAbsSourceResidual, MeshArtifactStats.WorstResidualPosition[0],MeshArtifactStats.WorstResidualPosition[1], MeshArtifactStats.WorstResidualPosition[2]); // The restored four-voxel relief creates sparse edge-curvature misses across // the full 512-tile view. Keep the connected-block rejection strict, while // allowing up to 4% scattered misses that do not form a visible patch. const uint64 RootBadLimit=std::max(64, MeshArtifactStats.CurvedEdgeChecks*40u/1000u); const double RootBadShare=MeshArtifactStats.CurvedEdgeChecks ?static_cast(MeshArtifactStats.CurvedEdgeRootBadVertices) /MeshArtifactStats.CurvedEdgeChecks:0.0; const bool bRootAuditPass=MeshArtifactStats.CurvedEdgeRootPatches==0 &&MeshArtifactStats.CurvedEdgeRootBadVertices<=RootBadLimit; std::printf("[MeshCurvedEdgeRootAudit] midpoint_edges=%llu bad_vertices=%llu bad_share=%.3f%% allowed=%llu patches=%llu max_midpoint_root_error=%.4f vox error_threshold=0.080 status=%s\n", static_cast(MeshArtifactStats.CurvedEdgeChecks), static_cast(MeshArtifactStats.CurvedEdgeRootBadVertices), RootBadShare*100.0,static_cast(RootBadLimit), static_cast(MeshArtifactStats.CurvedEdgeRootPatches), MeshArtifactStats.MaximumCurvedEdgeRootError, bRootAuditPass?"PASS":"FAIL"); std::printf("[MeshDetailGradientAudit] overlap_samples=%llu over_limit=%llu max_gradient=%.4f vox_per_vox limit=0.550 status=%s\n", static_cast(MeshArtifactStats.DetailGradientSamples), static_cast(MeshArtifactStats.DetailGradientOverLimit), MeshArtifactStats.MaximumDetailGradient, MeshArtifactStats.DetailGradientOverLimit==0?"PASS":"FAIL"); std::printf("[MeshSurfaceArtifactAudit] levels=0,1 tiles=%llu surface_vertices=%llu edge_vertices=%llu midpoint_band_vertices=%llu midpoint_share=%.2f%% visible_skirt_triangles=%llu hidden_same_lod_skirt_triangles=%llu exposed_skirt_triangles=%llu reverse_side_solid=%llu max_air_density=%.3f vox repeated_offset_patches=%llu field_residual_patches=%llu normal_mismatch_patches=%llu gradient_fallback_patches=%llu fallback_gradient_samples=%llu high_detail_vertices=%llu/%llu high_detail_patches=%llu max_detail_displacement=%.3f vox max_patch_dominance=%.3f status=%s\n", static_cast(MeshArtifactStats.Tiles), static_cast(MeshArtifactStats.SurfaceVertices), static_cast(MeshArtifactStats.EdgeVertices), static_cast(MeshArtifactStats.MidpointVertices),MidpointShare, static_cast(MeshArtifactStats.SkirtTriangles), static_cast(MeshArtifactStats.HiddenSameLodSkirtTriangles), static_cast(MeshArtifactStats.ExposedSkirtTriangles), static_cast(MeshArtifactStats.ReverseSideSolidSkirtTriangles), MeshArtifactStats.MaximumAirSkirtDensity, static_cast(MeshArtifactStats.RepeatedOffsetPatches), static_cast(MeshArtifactStats.FieldMismatchPatches), static_cast(MeshArtifactStats.NormalMismatchPatches), static_cast(MeshArtifactStats.GradientFallbackPatches), static_cast(MeshArtifactStats.GradientFallbackSamples), static_cast(MeshArtifactStats.HighDetailDisplacementSamples), static_cast(MeshArtifactStats.DetailDisplacementSamples), static_cast(MeshArtifactStats.DetailDisplacementPatches), MeshArtifactStats.MaximumDetailDisplacement, MeshArtifactStats.MaximumPatchDominance, MeshArtifactStats.ExposedSkirtTriangles==0&&MeshArtifactStats.RepeatedOffsetPatches==0 &&MeshArtifactStats.FieldMismatchPatches==0 &&MeshArtifactStats.NormalMismatchPatches==0 &&MeshArtifactStats.GradientFallbackPatches==0 &&MeshArtifactStats.DetailDisplacementPatches==0 &&bRootAuditPass &&MeshArtifactStats.DetailGradientOverLimit==0?"PASS":"FAIL"); std::printf("[CoarsePanelAudit] tiles=%llu planar_open_components=%llu off_surface_panels=%llu panel_triangles=%llu max_source_error=%.3f vox status=%s\n", static_cast(CoarsePanelStats.Tiles), static_cast(CoarsePanelStats.PlanarOpenComponents), static_cast(CoarsePanelStats.OffSurfacePanels), static_cast(CoarsePanelStats.Triangles), CoarsePanelStats.MaximumSourceErrorVoxels, CoarsePanelStats.OffSurfacePanels==0?"PASS":"FAIL"); } for(int32 Level=0;Level<=MaxLevels;++Level) { if(TilesByLevel[Level]==0)continue; if(bHashDensity||!BakeCachePath.empty()) std::printf("[StreamLevel] lod=%d tiles=%llu samples=%.3fM worker_sum=%.3fs first_ready=%.3fs complete=%.3fs worker_busy=%.1f%% payload_alloc=%.2fMiB viewer_output=%.2fMiB vertices=%llu indices=%llu density_hash=0x%016llx mesh_hash=0x%016llx payload_hash=0x%016llx topology_hash=0x%016llx\n", Level,static_cast(TilesByLevel[Level]), static_cast(SamplesByLevel[Level])/1.0e6,WorkerSecondsByLevel[Level], FirstCompletionByLevel[Level],LastCompletionByLevel[Level], 100.0*WorkerSecondsByLevel[Level]/(WorkerCount*std::max(0.001,LastCompletionByLevel[Level])), static_cast(MeshPayloadAllocatedBytesByLevel[Level])/1048576.0, static_cast(OutputBytesByLevel[Level])/1048576.0, static_cast(VerticesByLevel[Level]), static_cast(IndicesByLevel[Level]), static_cast(HashTileRows(HashRows[Level])), static_cast(HashTileRows(MeshHashRows[Level])), static_cast(HashTileRows(PayloadHashRows[Level])), static_cast(HashTileRows(TopologyHashRows[Level]))); else std::printf("[StreamLevel] lod=%d tiles=%llu samples=%.3fM worker_sum=%.3fs first_ready=%.3fs complete=%.3fs worker_busy=%.1f%% payload_alloc=%.2fMiB viewer_output=%.2fMiB vertices=%llu indices=%llu hash=off\n", Level,static_cast(TilesByLevel[Level]), static_cast(SamplesByLevel[Level])/1.0e6,WorkerSecondsByLevel[Level], FirstCompletionByLevel[Level],LastCompletionByLevel[Level], 100.0*WorkerSecondsByLevel[Level]/(WorkerCount*std::max(0.001,LastCompletionByLevel[Level])), static_cast(MeshPayloadAllocatedBytesByLevel[Level])/1048576.0, static_cast(OutputBytesByLevel[Level])/1048576.0, static_cast(VerticesByLevel[Level]), static_cast(IndicesByLevel[Level])); } if(!BakeCachePath.empty()) { std::string CacheError; if(!FStandaloneMeshCache::Save(BakeCachePath,CacheMetadata,CacheTiles,CacheError)) { std::fprintf(stderr,"[MeshCacheBake] failed: %s\n",CacheError.c_str()); return 8; } const uint64 Bytes=std::filesystem::file_size(BakeCachePath); std::printf("[MeshCacheBake] saved %zu tiles, %.2f MiB to %s\n",CacheTiles.size(), static_cast(Bytes)/1048576.0,BakeCachePath.c_str()); } if(Finished!=DesiredTotal||FullDetailFinished!=FullDetailExpected)return 6; if(bShardAudit&&(MeshSheetStats.ThinSheets!=0||MeshSheetStats.SmallComponentsInView!=0))return 13; if(bShardAudit&&CoreWorld&&(MeshArtifactStats.ExposedSkirtTriangles!=0 ||MeshArtifactStats.RepeatedOffsetPatches!=0||MeshArtifactStats.FieldMismatchPatches!=0 ||MeshArtifactStats.NormalMismatchPatches!=0||MeshArtifactStats.GradientFallbackPatches!=0 ||MeshArtifactStats.CurvedEdgeRootPatches!=0 ||MeshArtifactStats.CurvedEdgeRootBadVertices>std::max( 64,MeshArtifactStats.CurvedEdgeChecks*40u/1000u) ||MeshArtifactStats.DetailGradientOverLimit!=0))return 13; if(bShardAudit&&CoreWorld&&CoarsePanelStats.OffSurfacePanels!=0)return 13; if(FarAudit) { FarAudit->Finalize(); FarAudit->Print(); if(!FarAudit->Passing())return 14; } return 0; } int RunEditTransactionBenchmark(FStandaloneOwnerWorld& World,VoxelForgeCore::World& Shape, const FVector& CameraPositionVoxels,int32 WorkerCount) { using Clock=std::chrono::steady_clock; // Place the spell across the LOD0/LOD1 clipmap seam so one edit exercises every visible // level it intersects, instead of timing only the center LOD0 tiles. const double X=CameraPositionVoxels.X+3.0*CHUNK_SIZE; const double Y=CameraPositionVoxels.Y,Z=CameraPositionVoxels.Z; FStandaloneDesiredTileSet Desired=StandaloneWorldMesher::BuildDesiredSet(World,CameraPositionVoxels); const auto CoreDesired=Shape.desiredTiles( {CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z}); Desired.Tiles.clear();Desired.Tiles.reserve(CoreDesired.size()); std::vector CoreKeys;CoreKeys.reserve(CoreDesired.size()); for(const auto& Key:CoreDesired) { Desired.Tiles.emplace_back(FIntVector(Key.coordinate.x,Key.coordinate.y,Key.coordinate.z),Key.lod); CoreKeys.push_back(Key); } VoxelForgeCore::EditTransaction Transaction;Transaction.sequence=1;Transaction.brushes.resize(3); Transaction.brushes[0].shape=VoxelForgeCore::EditBrush::Shape::sphere; Transaction.brushes[0].operation=VoxelForgeCore::EditBrush::Operation::carve; Transaction.brushes[0].a={X,Y,Z};Transaction.brushes[0].radius=20.0; Transaction.brushes[1].shape=VoxelForgeCore::EditBrush::Shape::roundedBox; Transaction.brushes[1].operation=VoxelForgeCore::EditBrush::Operation::carve; Transaction.brushes[1].a={X,Y,Z+12.0};Transaction.brushes[1].halfExtent={11.0,11.0,4.0}; Transaction.brushes[1].rounding=3.0; Transaction.brushes[2].shape=VoxelForgeCore::EditBrush::Shape::capsule; Transaction.brushes[2].operation=VoxelForgeCore::EditBrush::Operation::addRock; Transaction.brushes[2].a={X-22.0,Y,Z-8.0};Transaction.brushes[2].b={X+22.0,Y,Z-8.0}; Transaction.brushes[2].radius=3.0; const auto EditStart=Clock::now(); std::string EditError; const auto Edit=Shape.applyEditTransaction(Transaction,CoreKeys,EditError); if(!Edit){std::fprintf(stderr,"[EditTransaction] rejected: %s\n",EditError.c_str());return 9;} std::vector Affected;Affected.reserve(128); std::array AffectedByLevel{},FinishedByLevel{}; for(const auto& LodTiles:Edit->affectedByLod) { for(const auto& Key:LodTiles) { const FVoxelTileKey Tile(FIntVector(Key.coordinate.x,Key.coordinate.y,Key.coordinate.z),Key.lod); Affected.push_back(Tile); if(Tile.Level>=0&&Tile.Level<=MaxLevels)++AffectedByLevel[Tile.Level]; } } if(Affected.empty()) { std::fprintf(stderr,"[EditTransaction] failed: no desired tiles intersect the edit bounds.\n"); return 9; } FStandaloneStreamingGenerator Streamer(World,WorkerCount,false,nullptr,-1, false,false,false,false,&Shape); Streamer.SetDesiredTileFilter(Affected); const auto Start=Clock::now(); const FStandaloneStreamingUpdate Update=Streamer.Start(CameraPositionVoxels); int32 Finished=0; double WorkerSeconds=0.0; while(Finished Ready=Streamer.TakeReady(); if(Ready.empty()){std::this_thread::sleep_for(std::chrono::milliseconds(1));continue;} for(const FStandaloneCpuTile& Tile:Ready) { ++Finished;WorkerSeconds+=Tile.WorkerSeconds; if(Tile.Key.Level>=0&&Tile.Key.Level<=MaxLevels)++FinishedByLevel[Tile.Key.Level]; } } const double RemeshWall=std::chrono::duration(Clock::now()-Start).count(); Streamer.Stop(); std::printf("[EditTransaction] operation=crater_batch transaction_count=1 brushes=3 diameter=10.0m offset_from_player=%.2fm affected_tiles=%d/%zu workers=%d cache_hits=%llu remesh_wall=%.3fs worker_sum=%.3fs edit_to_ready=%.3fs status=%s\n", 3.0*CHUNK_SIZE*VOXEL_SIZE/100.0, Finished,Affected.size(),WorkerCount,static_cast(Streamer.GetCacheHits()), RemeshWall,WorkerSeconds,std::chrono::duration(Clock::now()-EditStart).count(), Finished==static_cast(Affected.size())?"PASS":"FAIL"); for(int32 Level=0;Level<=MaxLevels;++Level) if(AffectedByLevel[Level]) std::printf("[EditTransactionLevel] lod=%d tiles=%llu remeshed=%llu status=%s\n",Level, static_cast(AffectedByLevel[Level]), static_cast(FinishedByLevel[Level]), AffectedByLevel[Level]==FinishedByLevel[Level]?"PASS":"FAIL"); return Finished==static_cast(Affected.size())?0:10; } bool MakeRegionBuildRequest(std::span tiles, const VoxelForgeCore::WorldConfiguration& config,int32 workers, VoxelForgeCore::DetailVariant detail,bool roundTunnels,bool enhancedWalls, VoxelForgeCore::ShapeBuildRequest& request,std::string& error) { FIntVector fineMin(MAX_int32,MAX_int32,MAX_int32),fineMax(MIN_int32,MIN_int32,MIN_int32); FIntVector clipMin(MAX_int32,MAX_int32,MAX_int32),clipMax(MIN_int32,MIN_int32,MIN_int32); for(const auto& key:tiles) { if(key.lod<0||key.lod>8){error="desired tile has an invalid LOD";return false;} const int32 extent=CHUNK_SIZE<(static_cast(key.coordinate.x)*extent), static_cast(static_cast(key.coordinate.y)*extent), static_cast(static_cast(key.coordinate.z)*extent)); for(int32 axis=0;axis<3;++axis) { (&clipMin.X)[axis]=std::min((&clipMin.X)[axis],(&origin.X)[axis]); (&clipMax.X)[axis]=std::max((&clipMax.X)[axis],(&origin.X)[axis]+extent); if(key.lod(std::clamp(workers,1,16)); request.detail=detail;request.roundTunnels=roundTunnels; request.enhancedTunnelWalls=enhancedWalls;request.includeFarWorld=false; return true; } int RunTilePathHashAudit(VoxelForgeCore::World& base, const VoxelForgeCore::ResolvedWorldSnapshot& snapshot, const VoxelForgeCore::JobScheduler& scheduler,const FVector& camera, int32 workers,VoxelForgeCore::DetailVariant detail,bool roundTunnels, bool enhancedWalls) { const auto baseTiles=base.desiredTiles({camera.X,camera.Y,camera.Z}); const auto& config=base.configuration(); if(baseTiles.empty()) {std::fprintf(stderr,"[TilePathHashAudit] camera window is empty.\n");return 11;} constexpr int32 TargetChunkOffset=40; const int32 CameraChunkX=FMath::FloorToInt(camera.X/CHUNK_SIZE); const int32 CameraChunkY=FMath::FloorToInt(camera.Y/CHUNK_SIZE); const int32 CameraChunkZ=FMath::FloorToInt(camera.Z/CHUNK_SIZE); const VoxelForgeCore::TileKey target{{CameraChunkX+TargetChunkOffset, CameraChunkY,CameraChunkZ},0}; const FVector alternateCamera((target.coordinate.x+0.5)*CHUNK_SIZE,camera.Y,camera.Z); const auto alternateTiles=base.desiredTiles( {alternateCamera.X,alternateCamera.Y,alternateCamera.Z}); if(alternateTiles.empty()) {std::fprintf(stderr,"[TilePathHashAudit] target camera window is empty.\n");return 11;} VoxelForgeCore::TileGenerationOptions options;options.hashDensity=true; std::string error; const std::array pageTiles={target}; std::size_t pageTilesA=0; if(!base.compileTileRegion(pageTiles,static_cast(std::clamp(workers,1,16)), scheduler,error,&pageTilesA,nullptr,false)) {std::fprintf(stderr,"[TilePathHashAudit] path-A page compile failed: %s\n",error.c_str());return 11;} auto pathA=base.generateTile(target,options,error); if(!pathA){std::fprintf(stderr,"[TilePathHashAudit] path-A generation failed: %s\n",error.c_str());return 11;} VoxelForgeCore::World alternate(snapshot); VoxelForgeCore::ShapeBuildRequest alternateRequest; if(!MakeRegionBuildRequest(alternateTiles,config,workers,detail,roundTunnels, enhancedWalls,alternateRequest,error) ||!alternate.compile(alternateRequest,scheduler,error)) {std::fprintf(stderr,"[TilePathHashAudit] alternate camera compile failed: %s\n",error.c_str());return 11;} std::size_t pageTilesB=0; auto pathB=alternate.generateTile(target,options,error); if(!pathB){std::fprintf(stderr,"[TilePathHashAudit] path-B generation failed: %s\n",error.c_str());return 11;} const auto Same=[&](const VoxelForgeCore::TileMesh& a,const VoxelForgeCore::TileMesh& b) { return a.densityHash==b.densityHash&&a.meshHash==b.meshHash &&a.payloadHash==b.payloadHash&&a.topologyHash==b.topologyHash; }; const int32 CameraDeltaX=static_cast(std::lround(alternateCamera.X-camera.X)); const bool pass=pageTilesA==1&&pageTilesB==0&&Same(*pathA,*pathB); std::printf("[TilePathHashAudit] tile=(%d,%d,%d) lod=%d path_a=late_page path_b=initial_base camera_delta_vox=(%d,0,0) page_covered_tiles=(%zu,%zu) density=(0x%016llx,0x%016llx) mesh=(0x%016llx,0x%016llx) payload=(0x%016llx,0x%016llx) topology=(0x%016llx,0x%016llx) status=%s\n", target.coordinate.x,target.coordinate.y,target.coordinate.z,target.lod,CameraDeltaX, pageTilesA,pageTilesB, static_cast(pathA->densityHash), static_cast(pathB->densityHash), static_cast(pathA->meshHash), static_cast(pathB->meshHash), static_cast(pathA->payloadHash), static_cast(pathB->payloadHash), static_cast(pathA->topologyHash), static_cast(pathB->topologyHash),pass?"PASS":"FAIL"); VoxelForgeCore::World analyticForward(snapshot),analyticReverse(snapshot); VoxelForgeCore::ShapeBuildRequest forwardRequest,reverseRequest; const FVector reverseCamera((target.coordinate.x+TargetChunkOffset+0.5)*CHUNK_SIZE, camera.Y,camera.Z); const auto reverseTiles=base.desiredTiles( {reverseCamera.X,reverseCamera.Y,reverseCamera.Z}); if(!MakeRegionBuildRequest(baseTiles,config,workers,detail,roundTunnels, enhancedWalls,forwardRequest,error) ||!analyticForward.compile(forwardRequest,scheduler,error) ||reverseTiles.empty() ||!MakeRegionBuildRequest(reverseTiles,config,workers,detail,roundTunnels, enhancedWalls,reverseRequest,error) ||!analyticReverse.compile(reverseRequest,scheduler,error)) {std::fprintf(stderr,"[TilePathHashDirections] setup failed: %s\n",error.c_str());return 11;} std::size_t analyticForwardCovered=0,analyticReverseCovered=0; VoxelForgeCore::TileRegionCompileStats forwardStats,reverseStats; if(!analyticForward.compileTileRegion(pageTiles,static_cast(std::clamp(workers,1,16)), scheduler,error,&analyticForwardCovered,&forwardStats,true) ||!analyticReverse.compileTileRegion(pageTiles,static_cast(std::clamp(workers,1,16)), scheduler,error,&analyticReverseCovered,&reverseStats,true)) {std::fprintf(stderr,"[TilePathHashDirections] region compile failed: %s\n",error.c_str());return 11;} auto analyticPathForward=analyticForward.generateTile(target,options,error); auto analyticPathReverse=analyticReverse.generateTile(target,options,error); if(!analyticPathForward||!analyticPathReverse) {std::fprintf(stderr,"[TilePathHashDirections] tile generation failed: %s\n",error.c_str());return 11;} const bool analyticDirectionsSame=Same(*analyticPathForward,*analyticPathReverse); const bool packedAnalyticRenderSame=pathA->meshHash==analyticPathForward->meshHash &&pathA->payloadHash==analyticPathForward->payloadHash &&pathA->topologyHash==analyticPathForward->topologyHash; const bool packedAnalyticDensitySame=pathA->densityHash==analyticPathForward->densityHash; std::printf("[TilePathHashDirections] tile=(%d,%d,%d) lod=%d approach_deltas=(-%d,+%d) regions=(%zu,%zu) density=(0x%016llx,0x%016llx) mesh=(0x%016llx,0x%016llx) payload=(0x%016llx,0x%016llx) topology=(0x%016llx,0x%016llx) status=%s\n", target.coordinate.x,target.coordinate.y,target.coordinate.z,target.lod, TargetChunkOffset,TargetChunkOffset,analyticForwardCovered,analyticReverseCovered, static_cast(analyticPathForward->densityHash), static_cast(analyticPathReverse->densityHash), static_cast(analyticPathForward->meshHash), static_cast(analyticPathReverse->meshHash), static_cast(analyticPathForward->payloadHash), static_cast(analyticPathReverse->payloadHash), static_cast(analyticPathForward->topologyHash), static_cast(analyticPathReverse->topologyHash), analyticDirectionsSame&&analyticForwardCovered==1&&analyticReverseCovered==1?"PASS":"FAIL"); std::printf("[TilePathPackedAnalyticParity] tile=(%d,%d,%d) density=(0x%016llx,0x%016llx) density_representation=%s mesh=(0x%016llx,0x%016llx) payload=(0x%016llx,0x%016llx) topology=(0x%016llx,0x%016llx) status=%s\n", target.coordinate.x,target.coordinate.y,target.coordinate.z, static_cast(pathA->densityHash), static_cast(analyticPathForward->densityHash), packedAnalyticDensitySame?"same":"different", static_cast(pathA->meshHash), static_cast(analyticPathForward->meshHash), static_cast(pathA->payloadHash), static_cast(analyticPathForward->payloadHash), static_cast(pathA->topologyHash), static_cast(analyticPathForward->topologyHash), packedAnalyticRenderSame?"PASS":"FAIL"); return pass&&analyticDirectionsSame&&analyticForwardCovered==1 &&analyticReverseCovered==1&&packedAnalyticRenderSame?0:12; } std::int64_t WorldAssemblyFixed(double voxels) {return static_cast(std::llround(voxels*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel));} std::int64_t WorldAssemblyQ16(double value) {return static_cast(std::llround(value*65536.0));} std::int64_t WorldAssemblyWavelength(double frequency,double fallbackVoxels) { const double wavelength=std::isfinite(frequency)&&frequency>0.0?1.0/frequency:fallbackVoxels; return std::max(1,WorldAssemblyFixed(wavelength)); } uint64 WorldAssemblyFeatureId(uint32 seed,int64 x,int64 y,uint32 kind) { uint64 hash=14695981039346656037ull; const auto add=[&](uint64 value,int bytes) { for(int i=0;i(value>>(8*i));hash*=1099511628211ull;} }; add(seed,4);add(static_cast(x),8);add(static_cast(y),8);add(kind,4); return hash?hash:1; } bool BuildFiniteStrateRoute(VoxelForgeCore::WorldAssemblyRecipeV1& recipe, VoxelForgeCore::WorldAssemblyStratumPlanV1& stratum,std::uint64_t& tested, std::uint64_t& gradeRejected,std::uint64_t& sweepRejected,std::string& error) { using namespace VoxelForgeCore; constexpr std::int64_t PlayerRadiusQ=348; // 0.34 m in Core's 0.25 m voxel scale. constexpr std::int64_t PlayerHeightQ=1802; // 1.76 m in Core's 0.25 m voxel scale. constexpr std::int64_t HalfHeightQ=PlayerHeightQ/2; constexpr std::int64_t StepQ=128; // 0.5 Core voxel, finer than the density lattice. constexpr std::int64_t ProbeRadiusQ=174; constexpr std::int64_t SupportDepthQ=256; constexpr std::int64_t GradeQ16=17560; // tan(15 degrees), rounded upward. constexpr std::int64_t RouteRadiusQ=4*WorldAssemblySubvoxelsPerVoxel; struct Direction {std::int32_t x,y;}; constexpr std::array directions{{ {65536,0},{46341,46341},{0,65536},{-46341,46341}, {-65536,0},{-46341,-46341},{0,-65536},{46341,-46341}}}; struct Candidate { std::int64_t score=0; std::int32_t centerX=0,centerY=0,direction=0; std::vector points; }; auto& constraints=stratum.routeConstraints; constraints.version=1; constraints.capsuleRadiusSubvoxels=PlayerRadiusQ; constraints.capsuleHeightSubvoxels=PlayerHeightQ; constraints.maximumGradeQ16=GradeQ16; constraints.sweepSpacingSubvoxels=StepQ; constraints.supportProbeRadiusSubvoxels=ProbeRadiusQ; constraints.supportSearchDepthSubvoxels=SupportDepthQ; constraints.minimumClearanceSubvoxels=8; constraints.minimumSupportProbes=3; const Heightfield2D finalField(recipe,stratum); if(!finalField.isValid()) {error="route planner received an invalid final composed field";return false;} std::vector candidates; constexpr std::int32_t halfLength=128; constexpr std::int32_t waypointSpacing=8; for(std::int32_t centerY=-256;centerY<=256;centerY+=64) for(std::int32_t centerX=-256;centerX<=256;centerX+=64) for(std::int32_t directionIndex=0;directionIndex(directions.size());++directionIndex) { Candidate candidate; candidate.centerX=centerX;candidate.centerY=centerY;candidate.direction=directionIndex; candidate.points.reserve(33); std::int64_t previousGround=0,previousX=0,previousY=0; bool gradePass=true; for(std::int32_t index=0;index<=32;++index) { const std::int64_t along=(index-16)*waypointSpacing; const std::int64_t x=centerX+std::llround( static_cast(along)*directions[directionIndex].x/65536.0); const std::int64_t y=centerY+std::llround( static_cast(along)*directions[directionIndex].y/65536.0); const auto column=finalField.point(WorldAssemblyFixed(static_cast(x)), WorldAssemblyFixed(static_cast(y)),0); const std::int64_t horizontalQ=static_cast(std::llround( std::hypot(static_cast(x-previousX),static_cast(y-previousY)) *WorldAssemblySubvoxelsPerVoxel)); if(index>0) { const std::int64_t riseQ=std::abs(column.groundHeightSubvoxels-previousGround); if(horizontalQ==0||riseQ*65536>horizontalQ*GradeQ16) {gradePass=false;break;} candidate.score+=riseQ*65536/std::max(1,horizontalQ); } WorldAssemblyRoutePointV1 point; point.positionSubvoxels={WorldAssemblyFixed(static_cast(x)), WorldAssemblyFixed(static_cast(y)),column.groundHeightSubvoxels+HalfHeightQ}; point.radiusSubvoxels=RouteRadiusQ; point.stableFeatureId=WorldAssemblyFeatureId(recipe.seed, static_cast(x),static_cast(y), 0x52540000u+static_cast(index)); candidate.points.push_back(point); previousGround=column.groundHeightSubvoxels;previousX=x;previousY=y; } ++tested; if(gradePass)candidates.push_back(std::move(candidate)); else ++gradeRejected; } std::stable_sort(candidates.begin(),candidates.end(),[](const Candidate& a,const Candidate& b) { if(a.score!=b.score)return a.score0) for(std::size_t pointIndex=0;pointIndex0) std::printf("[WorldAssemblerRouteRepaired] uniform_lift_q=%lld support_limit_q=%lld\n", static_cast(liftQ),static_cast(SupportDepthQ)); return true; } if(audit.blockedCapsuleSamples==0||liftQ>=MaximumRepairLiftQ)break; const std::int64_t needed=std::max(1, constraints.minimumClearanceSubvoxels-audit.minimumClearanceSubvoxels); const std::int64_t steps=(needed+RepairStepQ-1)/RepairStepQ; const std::int64_t nextLift=std::max(liftQ+RepairStepQ,liftQ+steps*RepairStepQ); if(nextLift>MaximumRepairLiftQ)break; liftQ=nextLift; ++repairAttempt; } if(sweepAttempt<3) std::printf("[WorldAssemblerRouteCandidateRejected] ordinal=%llu blocked=%llu unsupported=%llu grade_failures=%llu minimum_clearance_q=%lld\n", static_cast(sweepAttempt), static_cast(lastAudit.blockedCapsuleSamples), static_cast(lastAudit.unsupportedCenterSamples), static_cast(lastAudit.gradeFailures), static_cast(lastAudit.minimumClearanceSubvoxels)); ++sweepAttempt; ++sweepRejected; } std::printf("[WorldAssemblerRouteSearchFailed] tested=%llu grade_rejected=%llu sweepable_candidates=%llu sweep_rejected=%llu last_blocked=%llu last_unsupported=%llu last_grade_failures=%llu\n", static_cast(tested),static_cast(gradeRejected), static_cast(candidates.size()),static_cast(sweepRejected), static_cast(lastAudit.blockedCapsuleSamples), static_cast(lastAudit.unsupportedCenterSamples), static_cast(lastAudit.gradeFailures)); std::printf("[WorldAssemblerRouteRepairSummary] repair_attempts=%llu\n", static_cast(repairAttempt)); stratum.route.clear(); error="finite-strate route candidates failed the composed-field capsule and support sweep"; return false; } bool AttachRound1WorldAssemblyPrototype(FStandaloneOwnerWorld& owner,VFJson::Value& root, std::string& error,const std::string& manifestOutputPath) { if(!owner.Manager||!owner.Generator) {error="world assembler prototype needs the resolved standalone owner world";return false;} int32 surfaceChunkZ=0,topChunkZ=0,bottomChunkZ=0; bool foundSurface=false; for(int32 chunkZ=1024;chunkZ>=-4096;--chunkZ) { if(owner.Manager->GetGeneratorTypeForChunk(FIntVector(0,0,chunkZ)) !=ECaveGeneratorType::SurfaceWorld)continue; surfaceChunkZ=chunkZ; foundSurface=owner.Manager->GetStrateChunkZBounds(chunkZ,topChunkZ,bottomChunkZ); break; } if(!foundSurface) {error="world assembler prototype could not find a finite SurfaceWorld strate";return false;} const FIntVector chunk(0,0,surfaceChunkZ); const FSurfaceGenerationParams surface=owner.Manager->GetSurfaceParamsForChunk(chunk); const FBiomeContext biomeContext=owner.Manager->GetBiomeContextForChunk(chunk); const std::int64_t bottomVoxel=static_cast(bottomChunkZ)*CHUNK_SIZE; const std::int64_t heightVoxels=static_cast(topChunkZ-bottomChunkZ+1)*CHUNK_SIZE; const FBiomeMapParams& map=biomeContext.Map; const UVoxelStrateDefinition* definition=owner.Manager->GetStrateForChunk(chunk); VoxelForgeCore::WorldAssemblyManifest manifest; auto& recipe=manifest.recipe; recipe.seed=static_cast(owner.Seed); recipe.biomeCellSizeSubvoxels=WorldAssemblyFixed(map.CellSize); recipe.biomeWarpSubvoxels=WorldAssemblyFixed(map.WarpStrength); recipe.biomeWarpWavelengthSubvoxels=WorldAssemblyWavelength(map.WarpFrequency,556.0); recipe.biomeBorderBlendSubvoxels=WorldAssemblyFixed(map.BorderBlend); recipe.biomeClimateReliefWavelengthSubvoxels=WorldAssemblyWavelength(map.ReliefFrequency,3333.0); recipe.biomeClimateMoistureWavelengthSubvoxels=WorldAssemblyWavelength(map.MoistureFrequency,2500.0); recipe.biomeClimateReliefContrastQ16=WorldAssemblyQ16(map.ReliefContrast); const auto makeProfile=[&](uint32 stableId,const FSurfaceGenerationParams& params, const FBiomeResolved* climate) { VoxelForgeCore::WorldAssemblyBiomeProfileV1 profile; profile.stableId=stableId; profile.baseHeightSubvoxels=WorldAssemblyFixed(static_cast(bottomVoxel) +static_cast(heightVoxels)*params.BaseGroundRelative); profile.continentAmplitudeSubvoxels=WorldAssemblyFixed(params.ElevationRange); profile.continentWavelengthSubvoxels=WorldAssemblyWavelength(params.ContinentFrequency,1000.0); profile.mountainAmplitudeSubvoxels=WorldAssemblyFixed(params.ElevationRange*params.MountainStrength); profile.mountainWavelengthSubvoxels=WorldAssemblyWavelength(params.MountainFrequency,500.0); profile.detailAmplitudeSubvoxels=WorldAssemblyFixed(params.SurfaceRoughness); profile.detailWavelengthSubvoxels=WorldAssemblyWavelength(params.DetailFrequency,25.0); profile.reliefMinimumQ16=climate?WorldAssemblyQ16(climate->ReliefMin):0; profile.reliefMaximumQ16=climate?WorldAssemblyQ16(climate->ReliefMax):65536; profile.moistureMinimumQ16=climate?WorldAssemblyQ16(climate->MoistureMin):0; profile.moistureMaximumQ16=climate?WorldAssemblyQ16(climate->MoistureMax):65536; profile.reliefStrengthQ16=WorldAssemblyQ16(params.ReliefStrength); profile.reliefContrastQ16=WorldAssemblyQ16(params.ReliefContrast); profile.reliefWavelengthSubvoxels=WorldAssemblyWavelength(params.ReliefFrequency,667.0); profile.heightWarpStrengthSubvoxels=WorldAssemblyFixed(params.HeightWarpStrength); profile.heightWarpWavelengthSubvoxels=WorldAssemblyWavelength(params.HeightWarpFrequency,125.0); profile.beachWidthSubvoxels=WorldAssemblyFixed(params.BeachWidth); profile.cliffStrengthQ16=WorldAssemblyQ16(params.CliffStrength); profile.cliffSlopeThresholdQ16=std::max(1,WorldAssemblyQ16(params.CliffSlopeThreshold)); profile.cliffSharpnessQ16=WorldAssemblyQ16(params.CliffSharpness); profile.cliffSampleDistanceSubvoxels=WorldAssemblyFixed(std::max(0.5f,params.CliffSampleDist)); const double structuralAbsBound=static_cast(params.ElevationRange) +static_cast(params.ElevationRange)*params.MountainStrength +2.0*params.SurfaceRoughness; const double cliffAbsBound=2.0*structuralAbsBound*params.CliffStrength*params.CliffSharpness; profile.cliffMaximumDisplacementSubvoxels=WorldAssemblyFixed(params.CliffStrength>0.0f ?std::max(1.0,cliffAbsBound):0.0); profile.hasCapProfile=true; profile.capHeightSubvoxels=WorldAssemblyFixed(static_cast(bottomVoxel) +static_cast(heightVoxels)*params.CeilingRelative); profile.capWarpStrengthSubvoxels=WorldAssemblyFixed(params.CeilingWarpStrength); profile.capWarpWavelengthSubvoxels=WorldAssemblyWavelength(params.CeilingWarpFrequency,100.0); profile.capUndulationSubvoxels=WorldAssemblyFixed(params.CeilingUndulation); profile.capWavelengthSubvoxels=WorldAssemblyWavelength(params.CeilingUndulationFrequency,500.0); profile.capDetailAmplitudeSubvoxels=WorldAssemblyFixed(params.CeilingRoughness); profile.capDetailWavelengthSubvoxels=WorldAssemblyWavelength(params.CeilingRoughnessFrequency,25.0); profile.capRidgeAmplitudeSubvoxels=WorldAssemblyFixed(params.CeilingRidgeStrength); profile.capRidgeWavelengthSubvoxels=WorldAssemblyWavelength(params.CeilingRidgeFrequency,50.0); return profile; }; if(biomeContext.IsValid()&&definition) { for(const FBiomeResolved& resolved:biomeContext.Biomes) { const UVoxelBiomeDefinition* biome=definition->Biomes.IsValidIndex(resolved.Index) ?definition->Biomes[resolved.Index]:nullptr; FSurfaceGenerationParams params=surface; if(biome&&biome->bOverrideTerrain&&biome->GeneratorType==ECaveGeneratorType::SurfaceWorld) { params=biome->SurfaceParams; params.StrateTopWorldZ=surface.StrateTopWorldZ; params.StrateBottomWorldZ=surface.StrateBottomWorldZ; params.BoundarySealThickness=surface.BoundarySealThickness; params.BaseDensity=surface.BaseDensity; params.WaterLevelRelative=surface.WaterLevelRelative; } recipe.biomes.push_back(makeProfile(0x1001u+static_cast(resolved.Index),params,&resolved)); } } if(recipe.biomes.empty())recipe.biomes.push_back(makeProfile(0x1001u,surface,nullptr)); VoxelForgeCore::WorldAssemblyStratumPlanV1 stratum; stratum.strateIndex=owner.Manager->GetStrateIndex( static_cast((static_cast(surfaceChunkZ*CHUNK_SIZE+CHUNK_SIZE/2))*VOXEL_SIZE)); stratum.topChunkZ=topChunkZ; stratum.bottomChunkZ=bottomChunkZ; const double strateBottom=static_cast(bottomVoxel); const double strateHeight=static_cast(heightVoxels); stratum.capHeightSubvoxels=WorldAssemblyFixed(strateBottom+strateHeight*surface.CeilingRelative); stratum.capUndulationSubvoxels=WorldAssemblyFixed(surface.CeilingUndulation); stratum.capWavelengthSubvoxels=WorldAssemblyWavelength(surface.CeilingUndulationFrequency,250.0); stratum.capDetailAmplitudeSubvoxels=WorldAssemblyFixed(surface.CeilingRoughness); stratum.capDetailWavelengthSubvoxels=WorldAssemblyWavelength(surface.CeilingRoughnessFrequency,25.0); stratum.capRidgeAmplitudeSubvoxels=WorldAssemblyFixed(surface.CeilingRidgeStrength); stratum.capRidgeWavelengthSubvoxels=WorldAssemblyWavelength(surface.CeilingRidgeFrequency,50.0); stratum.waterSurfaceSubvoxels=WorldAssemblyFixed(strateBottom+strateHeight*surface.WaterLevelRelative); stratum.waterEnabled=definition&&definition->bHasWater&&surface.WaterLevelRelative>0.0f; // Select a deterministic steep edge in the resolved owner field for a bounded shelf. // Selection d'une pente deterministe dans le champ resolu pour une saillie bornee. constexpr int probeSide=49,probeStep=32; std::array heights{}; std::array valid{}; for(int y=0;y((x-probeSide/2)*probeStep); const float py=static_cast((y-probeSide/2)*probeStep); float ceiling=0.0f; const std::size_t index=static_cast(y)*probeSide+x; valid[index]=owner.Generator->GetSurfaceHeightAt(px,py,topChunkZ,heights[index],ceiling)?1u:0u; } double steepest=0.0;int cliffX=0,cliffY=0;bool xAxis=true;int downhill=1; for(int y=1;y(y)*probeSide+x; if(!valid[center]||!valid[center-1]||!valid[center+1]||!valid[center-probeSide]||!valid[center+probeSide])continue; const double dx=static_cast(heights[center+1]-heights[center-1]); const double dy=static_cast(heights[center+probeSide]-heights[center-probeSide]); const double slope=(std::abs(dx)+std::abs(dy))/(4.0*probeStep); if(slope>steepest){steepest=slope;cliffX=(x-probeSide/2)*probeStep;cliffY=(y-probeSide/2)*probeStep; xAxis=std::abs(dx)>=std::abs(dy);downhill=(xAxis?dx:dy)>=0.0?-1:1;} } if(steepest>0.05) { float ground=0.0f,ceiling=0.0f; if(owner.Generator->GetSurfaceHeightAt(static_cast(cliffX),static_cast(cliffY), topChunkZ,ground,ceiling)) { VoxelForgeCore::WorldAssemblyFeatureV1 shelf; shelf.stableId=WorldAssemblyFeatureId(recipe.seed,cliffX,cliffY,0x4f564552u); shelf.type=4; constexpr int reach=72,width=36,height=64,feather=8; const int dirX=xAxis?downhill:0,dirY=xAxis?0:downhill; const int minX=xAxis?(dirX>0?cliffX-feather:cliffX-reach-feather) :cliffX-width-feather; const int maxX=xAxis?(dirX>0?cliffX+reach+feather:cliffX+feather) :cliffX+width+feather; const int minY=xAxis?cliffY-width-feather :(dirY>0?cliffY-feather:cliffY-reach-feather); const int maxY=xAxis?cliffY+width+feather :(dirY>0?cliffY+reach+feather:cliffY+feather); VoxelForgeCore::Heightfield2D baseField(recipe,stratum); double lowestGround=std::numeric_limits::infinity(); double highestGround=-std::numeric_limits::infinity(); for(int sampleY=minY;sampleY<=maxY;sampleY+=4) for(int sampleX=minX;sampleX<=maxX;sampleX+=4) { const auto sample=baseField.point(WorldAssemblyFixed(sampleX), WorldAssemblyFixed(sampleY),0); const double heightQ=static_cast(sample.groundHeightSubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; lowestGround=std::min(lowestGround,heightQ); highestGround=std::max(highestGround,heightQ); } if(!std::isfinite(lowestGround)||!std::isfinite(highestGround)) {error="world assembler cliff shelf could not bound its terrain columns";return false;} shelf.minimumSubvoxels={WorldAssemblyFixed(minX),WorldAssemblyFixed(minY), WorldAssemblyFixed(std::max(bottomVoxel,lowestGround-4.0))}; shelf.maximumSubvoxels={WorldAssemblyFixed(maxX),WorldAssemblyFixed(maxY), WorldAssemblyFixed(std::min((topChunkZ+1)*CHUNK_SIZE, highestGround+height+4.0))}; shelf.parametersSubvoxels={WorldAssemblyFixed(dirX),WorldAssemblyFixed(dirY), WorldAssemblyFixed(height),WorldAssemblyFixed(reach)}; stratum.features.push_back(shelf); } } std::uint64_t routeCandidates=0,routeGradeRejected=0,routeSweepRejected=0; if(!BuildFiniteStrateRoute(recipe,stratum,routeCandidates,routeGradeRejected, routeSweepRejected,error))return false; std::printf("[WorldAssemblerRoutePlan] candidates=%llu grade_rejected=%llu sweep_rejected=%llu accepted_points=%zu capsule_m=0.34x1.76 corridor_radius_vox=4 support_probe_points=5 minimum_support_probes=%u status=PASS\n", static_cast(routeCandidates), static_cast(routeGradeRejected), static_cast(routeSweepRejected),stratum.route.size(), stratum.routeConstraints.minimumSupportProbes); manifest.plan.strates.push_back(std::move(stratum)); if(!manifest.finalize(error))return false; const std::string manifestText=manifest.ToJson(); const auto roundTrip=VoxelForgeCore::WorldAssemblyManifest::FromJson(manifestText,error); if(!roundTrip||!roundTrip->validate(error)||roundTrip->ToJson()!=manifestText ||roundTrip->contentHash!=manifest.contentHash) {if(error.empty())error="world assembly canonical plan serialization did not round-trip";return false;} std::printf("[WorldAssemblerPlanSerialization] bytes=%zu canonical_round_trip=true route_points=%zu plan_hash=%016llx manifest_hash=%016llx status=PASS\n", manifestText.size(),manifest.plan.strates.front().route.size(), static_cast(manifest.plan.contentHash), static_cast(manifest.contentHash)); if(!manifestOutputPath.empty()) { const std::filesystem::path outputPath(manifestOutputPath); std::error_code directoryError; if(!outputPath.parent_path().empty()) std::filesystem::create_directories(outputPath.parent_path(),directoryError); if(directoryError) {error="could not create the world assembly manifest output directory";return false;} std::ofstream output(outputPath,std::ios::binary); if(!output) {error="could not open the world assembly manifest output path";return false;} output.write(manifestText.data(),static_cast(manifestText.size())); if(!output) {error="could not write the world assembly manifest payload";return false;} } VFJson::Value manifestJson; if(!VFJson::Parser(manifestText).Parse(manifestJson,error))return false; auto* rootObject=std::get_if(&root.Data); if(!rootObject) {error="owner snapshot root is not a JSON object";return false;} (*rootObject)["world_assembly"]=std::move(manifestJson); std::printf("[WorldAssemblerPrototype] recipe_version=%u evaluator_version=%u strata=%zu biomes=%zu strate_index=%d chunk_z=%d..%d serialized_bytes=%zu recipe_hash=%016llx plan_hash=%016llx manifest_hash=%016llx source=owner_surface_params_and_biome_map route_points=%zu features=%zu\n", manifest.recipe.schemaVersion,manifest.recipe.evaluatorVersion,manifest.plan.strates.size(), manifest.recipe.biomes.size(),manifest.plan.strates.front().strateIndex,topChunkZ,bottomChunkZ, manifestText.size(),static_cast(manifest.recipe.contentHash), static_cast(manifest.plan.contentHash), static_cast(manifest.contentHash),manifest.plan.strates.front().route.size(), manifest.plan.strates.front().features.size()); return true; } bool RunWorldAssemblerCapAudit(FStandaloneOwnerWorld& owner, const VoxelForgeCore::ResolvedWorldSnapshot& snapshot,VoxelForgeCore::World& world, VoxelForgeCore::Vec3d walkCameraVoxels) { // This audit follows the shipped owner manifest and Core clipmap, not the transient BuildHost fixture. // Cet audit suit le manifeste owner livre et le clipmap Core, pas le fixture BuildHost transitoire. constexpr std::int64_t Scale=VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; constexpr double Pi=3.14159265358979323846; constexpr double RayStepVoxels=128.0; constexpr double AgreementToleranceCm=2.0; constexpr double NegativeDatumOffsetCm=100.0; using FTileId=std::array; using FXYLod=std::array; const double VoxelSizeCm=static_cast(world.configuration().voxelSizeMicrons)/10000.0; const auto IdFor=[](const VoxelForgeCore::TileKey& key) {return FTileId{key.coordinate.x,key.coordinate.y,key.coordinate.z,key.lod};}; const auto FloorDiv64=[](std::int64_t value,std::int64_t divisor) { const std::int64_t quotient=value/divisor,remainder=value%divisor; return quotient-((remainder!=0&&remainder<0)?1:0); }; const auto* manifest=snapshot.worldAssembly(); if(!manifest||manifest->plan.strates.empty()) {std::fprintf(stderr,"[WorldAssemblerFarCapAudit] no SurfaceWorld plan; status=FAIL\n");return false;} const auto planIt=std::find_if(manifest->plan.strates.begin(),manifest->plan.strates.end(), [](const auto& plan){return !plan.route.empty();}); if(planIt==manifest->plan.strates.end()) {std::fprintf(stderr,"[WorldAssemblerFarCapAudit] no authored walk route; status=FAIL\n");return false;} const auto& plan=*planIt; const VoxelForgeCore::Heightfield2D field(manifest->recipe,plan); if(!field.isValid()) {std::fprintf(stderr,"[WorldAssemblerFarCapAudit] invalid Heightfield2D; status=FAIL\n");return false;} struct FView { VoxelForgeCore::Vec3d Origin{}; std::vector Keys; std::set KeySet; VoxelForgeCore::TileGenerationOptions Options; double ClipMinX=std::numeric_limits::infinity(); double ClipMinY=std::numeric_limits::infinity(); double ClipMaxX=-std::numeric_limits::infinity(); double ClipMaxY=-std::numeric_limits::infinity(); double ClipMaxZ=-std::numeric_limits::infinity(); }; const auto MakeView=[&](VoxelForgeCore::Vec3d origin) { FView view;view.Origin=origin; const FStandaloneDesiredTileSet native=StandaloneWorldMesher::BuildDesiredSet(owner, FVector(origin.x,origin.y,origin.z)); view.Options.bandMinZVoxel=native.bHasStrate ?native.StrateBottomChunkZ*CHUNK_SIZE:MIN_int32; view.Options.bandMaxZVoxel=native.bHasStrate ?(native.StrateTopChunkZ+1)*CHUNK_SIZE:MAX_int32; view.Keys=world.desiredTiles(origin); for(const auto& key:view.Keys) { view.KeySet.insert(IdFor(key)); const double extent=static_cast(CHUNK_SIZE<8)continue; view.ClipMinX=std::min(view.ClipMinX,key.coordinate.x*extent); view.ClipMinY=std::min(view.ClipMinY,key.coordinate.y*extent); view.ClipMaxX=std::max(view.ClipMaxX,(key.coordinate.x+1.0)*extent); view.ClipMaxY=std::max(view.ClipMaxY,(key.coordinate.y+1.0)*extent); } return view; }; const FView cameraView=MakeView(walkCameraVoxels); std::set farXY; for(const auto& key:cameraView.Keys) if(key.lod>=4&&key.lod<=8)farXY.insert({key.coordinate.x,key.coordinate.y,key.lod}); std::set capBands; std::uint64_t profileSamples=0,profileSamplesWithoutRoof=0; for(const FXYLod& xy:farXY) { const std::int32_t lod=xy[2]; const std::int64_t extent=static_cast(CHUNK_SIZE)<(xy[0])*extent; const std::int64_t originY=static_cast(xy[1])*extent; const std::int64_t gridStep=lod<5?std::min(128,1ll<=MIN_int32&&band<=MAX_int32) capBands.insert({xy[0],xy[1],static_cast(band),lod}); if(farCap%(extent*Scale)==0&&band>MIN_int32) capBands.insert({xy[0],xy[1],static_cast(band-1),lod}); } } struct FAgreement {std::int64_t X=0,Y=0;double FarZ=0.0;}; struct FGeometry { std::vector> DownwardTriangles; std::uint64_t CapTriangles=0; std::vector AgreementVertices; }; constexpr std::int64_t AgreementGrid=128*Scale; std::map geometryCache; std::string coreError; const auto GetGeometry=[&](const FTileId& id,const VoxelForgeCore::TileGenerationOptions& options) ->const FGeometry* { if(const auto found=geometryCache.find(id);found!=geometryCache.end())return &found->second; const VoxelForgeCore::TileKey key{{id[0],id[1],id[2]},id[3]}; const auto mesh=world.generateTile(key,options,coreError); if(!mesh)return nullptr; FGeometry geometry; geometry.CapTriangles=mesh->diagnostics.horizonCapTriangles; const std::size_t capIndexStart=mesh->indices.size() -static_cast(geometry.CapTriangles)*3u; for(std::size_t index=0;index+2indices.size();index+=3) { const auto ia=mesh->indices[index],ib=mesh->indices[index+1],ic=mesh->indices[index+2]; if(ia>=mesh->vertices.size()||ib>=mesh->vertices.size()||ic>=mesh->vertices.size())continue; const auto& a=mesh->vertices[ia];const auto& b=mesh->vertices[ib];const auto& c=mesh->vertices[ic]; if((a.normal.z+b.normal.z+c.normal.z)/3.0>=-0.05)continue; geometry.DownwardTriangles.push_back({ VoxelForgeCore::Vec3d{a.position.x/VoxelSizeCm,a.position.y/VoxelSizeCm,a.position.z/VoxelSizeCm}, VoxelForgeCore::Vec3d{b.position.x/VoxelSizeCm,b.position.y/VoxelSizeCm,b.position.z/VoxelSizeCm}, VoxelForgeCore::Vec3d{c.position.x/VoxelSizeCm,c.position.y/VoxelSizeCm,c.position.z/VoxelSizeCm}}); } for(std::size_t index=capIndexStart;indexindices.size();++index) { const std::uint32_t vertexIndex=mesh->indices[index]; if(vertexIndex>=mesh->vertices.size())continue; const auto& vertex=mesh->vertices[vertexIndex]; if(vertex.normal.z>=-0.35)continue; const std::int64_t x=static_cast(std::llround( vertex.position.x/VoxelSizeCm*Scale)); const std::int64_t y=static_cast(std::llround( vertex.position.y/VoxelSizeCm*Scale)); if(x%AgreementGrid!=0||y%AgreementGrid!=0)continue; geometry.AgreementVertices.push_back({x,y,vertex.position.z/VoxelSizeCm}); } return &geometryCache.emplace(id,std::move(geometry)).first->second; }; std::uint64_t requested=0,emitted=0,requestedWithoutTriangles=0,culled=0; std::uint64_t zeroAreaBoundaryTouches=0,unexplainedEmptyBands=0; std::map> byLod; std::set> agreementXY; std::vector agreementSamples;agreementSamples.reserve(128); for(const FTileId& id:capBands) { auto& count=byLod[id[3]];++count[0]; if(!cameraView.KeySet.contains(id)){++culled;++count[1];continue;} ++requested; const FGeometry* geometry=GetGeometry(id,cameraView.Options); if(geometry==nullptr) { std::fprintf(stderr,"[WorldAssemblerFarCapAudit] tile generation failed key=(%d,%d,%d,lod%d): %s\n", id[0],id[1],id[2],id[3],coreError.c_str());return false; } if(geometry->CapTriangles==0) { ++requestedWithoutTriangles;++count[3]; const std::int64_t extent=static_cast(VoxelForgeCore::CoreTileVoxelCount)<(128,1ll<(id[2])*extent*Scale; const std::int64_t maxZ=minZ+extent*Scale; const std::int64_t originX=static_cast(id[0])*extent; const std::int64_t originY=static_cast(id[1])*extent; std::uint64_t validSamples=0,boundarySamples=0,interiorSamples=0; for(std::int64_t y=0;y<=extent;y+=step) for(std::int64_t x=0;x<=extent;x+=step) { const auto column=field.point((originX+x)*Scale,(originY+y)*Scale,0); const std::int64_t farCap=field.farSurfaceCapHeightSubvoxels( (originX+x)*Scale,(originY+y)*Scale); if(farCap<=column.groundHeightSubvoxels||farCapmaxZ)continue; ++validSamples; if(farCap==minZ||farCap==maxZ)++boundarySamples; else ++interiorSamples; } const bool zeroAreaTouch=validSamples>0&&boundarySamples==validSamples &&interiorSamples==0; if(zeroAreaTouch)++zeroAreaBoundaryTouches;else ++unexplainedEmptyBands; std::printf("[WorldAssemblerFarCapEmptyBand] key=(%d,%d,%d,lod%d) valid_profile_samples=%llu boundary_samples=%llu interior_samples=%llu classification=%s\n", id[0],id[1],id[2],id[3],static_cast(validSamples), static_cast(boundarySamples),static_cast(interiorSamples), zeroAreaTouch?"zero_area_boundary_touch":"UNEXPLAINED"); continue; } ++emitted;++count[2]; for(const FAgreement& sample:geometry->AgreementVertices) { if(agreementSamples.size()>=128)break; if(!agreementXY.insert({sample.X,sample.Y}).second)continue; agreementSamples.push_back(sample); } } std::uint64_t agreementCompared=0; double maximumAgreementCm=0.0,maximumNegativeControlCm=0.0; FAgreement maximumAgreementSample{};double maximumAgreementNearRoot=0.0; for(const FAgreement& sample:agreementSamples) { const auto column=field.point(sample.X,sample.Y,0); const std::int64_t farCap=field.farSurfaceCapHeightSubvoxels(sample.X,sample.Y); if(farCap<=column.groundHeightSubvoxels)continue; const double x=static_cast(sample.X)/Scale,y=static_cast(sample.Y)/Scale; const double capVoxel=static_cast(farCap)/Scale; bool foundRoot=false;double nearRoot=0.0; for(double radius=4.0;radius<=4096.0;radius*=2.0) { double lo=capVoxel-radius,hi=capVoxel+radius; if(!(world.densityAt({x,y,lo})>=0.0f&&world.densityAt({x,y,hi})<0.0f))continue; for(int iteration=0;iteration<16;++iteration) {const double mid=(lo+hi)*0.5;if(world.densityAt({x,y,mid})>=0.0f)lo=mid;else hi=mid;} nearRoot=(lo+hi)*0.5;foundRoot=true;break; } if(!foundRoot)continue; const double sampleErrorCm=std::abs(sample.FarZ-nearRoot)*VoxelSizeCm; if(sampleErrorCm>maximumAgreementCm) {maximumAgreementCm=sampleErrorCm;maximumAgreementSample=sample;maximumAgreementNearRoot=nearRoot;} maximumNegativeControlCm=std::max(maximumNegativeControlCm, std::abs(sample.FarZ+NegativeDatumOffsetCm/VoxelSizeCm-nearRoot)*VoxelSizeCm); ++agreementCompared; } if(agreementCompared>0) { const double capVoxel=static_cast(field.farSurfaceCapHeightSubvoxels( maximumAgreementSample.X,maximumAgreementSample.Y))/Scale; const double x=static_cast(maximumAgreementSample.X)/Scale; const double y=static_cast(maximumAgreementSample.Y)/Scale; std::printf("[WorldAssemblerFarCapAgreementMax] xy_vox=(%.1f,%.1f) profile_cap_vox=%.4f far_cap_vox=%.4f near_root_vox=%.4f density_at_cap=%.4f density_below=%.4f density_above=%.4f\n", x,y,capVoxel,maximumAgreementSample.FarZ,maximumAgreementNearRoot, world.densityAt({x,y,capVoxel}),world.densityAt({x,y,capVoxel-4.0}), world.densityAt({x,y,capVoxel+4.0})); } const bool negativeControlDetected=agreementCompared>0 &&maximumNegativeControlCm>AgreementToleranceCm; std::printf("[WorldAssemblerFarCapCensus] view=owner_camera far_xy_tiles=%zu profile_samples=%llu samples_without_roof=%llu cap_bands=%zu requested=%llu emitted=%llu requested_without_triangles=%llu zero_area_boundary_touches=%llu unexplained_empty_bands=%llu culled_by_clipmap=%llu\n", farXY.size(),static_cast(profileSamples), static_cast(profileSamplesWithoutRoof),capBands.size(), static_cast(requested),static_cast(emitted), static_cast(requestedWithoutTriangles), static_cast(zeroAreaBoundaryTouches), static_cast(unexplainedEmptyBands),static_cast(culled)); for(const auto& [lod,count]:byLod) std::printf("[WorldAssemblerFarCapLod] lod=%d cap_bands=%llu culled=%llu emitted=%llu requested_without_triangles=%llu\n", lod,static_cast(count[0]),static_cast(count[1]), static_cast(count[2]),static_cast(count[3])); std::printf("[WorldAssemblerFarCapAgreement] status=%s shared_points=%llu max_far_near_cm=%.4f tolerance_cm=%.2f negative_control=100cm_datum_offset max_error_cm=%.4f detected=%d\n", agreementCompared>=32&&maximumAgreementCm<=AgreementToleranceCm&&negativeControlDetected?"PASS":"FAIL", static_cast(agreementCompared),maximumAgreementCm,AgreementToleranceCm, maximumNegativeControlCm,negativeControlDetected?1:0); constexpr std::array azimuths={0.0,45.0,90.0,135.0,180.0,225.0,270.0,315.0}; constexpr std::array elevations={5.0,10.0,12.0,15.0,30.0,45.0,60.0,75.0,90.0}; const auto dot3=[](const VoxelForgeCore::Vec3d& a,const VoxelForgeCore::Vec3d& b) {return a.x*b.x+a.y*b.y+a.z*b.z;}; const auto sub3=[](const VoxelForgeCore::Vec3d& a,const VoxelForgeCore::Vec3d& b) {return VoxelForgeCore::Vec3d{a.x-b.x,a.y-b.y,a.z-b.z};}; const auto cross3=[](const VoxelForgeCore::Vec3d& a,const VoxelForgeCore::Vec3d& b) {return VoxelForgeCore::Vec3d{a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x};}; const auto rayTriangle=[&](const VoxelForgeCore::Vec3d& origin,const VoxelForgeCore::Vec3d& direction, const std::array& triangle,double minDistance,double maxDistance) { const auto edge1=sub3(triangle[1],triangle[0]),edge2=sub3(triangle[2],triangle[0]); const auto p=cross3(direction,edge2);const double determinant=dot3(edge1,p); if(std::abs(determinant)<1.0e-12)return false; const double inverse=1.0/determinant;const auto t=sub3(origin,triangle[0]); const double u=dot3(t,p)*inverse;if(u< -1.0e-8||u>1.0+1.0e-8)return false; const auto q=cross3(t,edge1);const double v=dot3(direction,q)*inverse; if(v< -1.0e-8||u+v>1.0+1.0e-8)return false; const double distance=dot3(edge2,q)*inverse; return distance>=minDistance-1.0e-6&&distance<=maxDistance+1.0e-6; }; std::vector walkOrigins; walkOrigins.reserve(plan.route.size()+1); for(const auto& point:plan.route) walkOrigins.push_back({static_cast(point.positionSubvoxels[0])/Scale, static_cast(point.positionSubvoxels[1])/Scale, static_cast(point.positionSubvoxels[2])/Scale}); const auto sameCamera=std::find_if(walkOrigins.begin(),walkOrigins.end(),[&](const auto& point) {return std::abs(point.x-walkCameraVoxels.x)<1.0&&std::abs(point.y-walkCameraVoxels.y)<1.0 &&std::abs(point.z-walkCameraVoxels.z)<1.0;}); if(sameCamera==walkOrigins.end())walkOrigins.push_back(walkCameraVoxels); const VoxelForgeCore::Vec3d farStraightUpCamera{0.0,-1800.0*4.0,walkCameraVoxels.z}; const std::size_t farStraightUpIndex=walkOrigins.size(); walkOrigins.push_back(farStraightUpCamera); std::uint64_t rayCount=0,rayHits=0,profileCrossings=0,profileRoofCrossings=0; std::uint64_t missesNoProfileRoof=0,missesMesh=0,missesClipEdge=0; std::array raysByElevation{},hitsByElevation{}; std::vector firstMisses;firstMisses.reserve(8); for(std::size_t viewIndex=0;viewIndexview.ClipMaxX||view.ClipMinY>view.ClipMaxY)continue; const auto startColumn=field.point( static_cast(std::llround(view.Origin.x*Scale)), static_cast(std::llround(view.Origin.y*Scale)),0); const double startCap=static_cast(field.farSurfaceCapHeightSubvoxels( static_cast(std::llround(view.Origin.x*Scale)), static_cast(std::llround(view.Origin.y*Scale))))/Scale; for(std::size_t elevationIndex=0;elevationIndex::infinity(); if(direction.x>1.0e-9)edgeDistance=std::min(edgeDistance,(view.ClipMaxX-view.Origin.x)/direction.x); else if(direction.x< -1.0e-9)edgeDistance=std::min(edgeDistance,(view.ClipMinX-view.Origin.x)/direction.x); if(direction.y>1.0e-9)edgeDistance=std::min(edgeDistance,(view.ClipMaxY-view.Origin.y)/direction.y); else if(direction.y< -1.0e-9)edgeDistance=std::min(edgeDistance,(view.ClipMinY-view.Origin.y)/direction.y); if(direction.z>1.0e-9)edgeDistance=std::min(edgeDistance,(view.ClipMaxZ-view.Origin.z)/direction.z); if(!std::isfinite(edgeDistance)||edgeDistance<=0.0) {++missesClipEdge;continue;} bool profileCrossing=false,profileRoof=false; double previousDistance=0.0,previousDelta=view.Origin.z-startCap; for(double distance=std::min(RayStepVoxels,edgeDistance);;) { const auto column=field.point( static_cast(std::llround((view.Origin.x+direction.x*distance)*Scale)), static_cast(std::llround((view.Origin.y+direction.y*distance)*Scale)),0); const double cap=static_cast(field.farSurfaceCapHeightSubvoxels( static_cast(std::llround((view.Origin.x+direction.x*distance)*Scale)), static_cast(std::llround((view.Origin.y+direction.y*distance)*Scale))))/Scale; const double delta=view.Origin.z+direction.z*distance-cap; if(previousDelta<0.0&&delta>=0.0) { const double fraction=-previousDelta/(delta-previousDelta); const double hitX=view.Origin.x+direction.x*(previousDistance+(distance-previousDistance)*fraction); const double hitY=view.Origin.y+direction.y*(previousDistance+(distance-previousDistance)*fraction); const auto hitColumn=field.point(static_cast(std::llround(hitX*Scale)), static_cast(std::llround(hitY*Scale)),0); profileCrossing=true;++profileCrossings; profileRoof=field.farSurfaceCapHeightSubvoxels( static_cast(std::llround(hitX*Scale)), static_cast(std::llround(hitY*Scale))) >hitColumn.groundHeightSubvoxels; if(profileRoof)++profileRoofCrossings; break; } previousDistance=distance;previousDelta=delta; if(distance>=edgeDistance)break; distance=std::min(distance+RayStepVoxels,edgeDistance); } bool meshHit=false,intersectedRequestedTile=false,intersectedEmptyTile=false; const auto& rayOrigin=view.Origin; for(const auto& key:view.Keys) { const double extent=static_cast(CHUNK_SIZE<maxBounds[axis]){intersects=false;break;}continue;} double tNear=(minBounds[axis]-origins[axis])/directions[axis]; double tFar=(maxBounds[axis]-origins[axis])/directions[axis]; if(tNear>tFar)std::swap(tNear,tFar); enter=std::max(enter,tNear);exit=std::min(exit,tFar); if(enter>exit){intersects=false;break;} } if(!intersects||exit<0.0||enter>edgeDistance)continue; intersectedRequestedTile=true; const FGeometry* geometry=GetGeometry(IdFor(key),view.Options); if(geometry==nullptr) {std::fprintf(stderr,"[WorldAssemblerFarCapAudit] ray tile generation failed: %s\n",coreError.c_str());return false;} if(geometry->DownwardTriangles.empty()){intersectedEmptyTile=true;continue;} for(const auto& triangle:geometry->DownwardTriangles) if(rayTriangle(rayOrigin,direction,triangle,std::max(0.0,enter),std::min(edgeDistance,exit))) {meshHit=true;break;} if(meshHit)break; } if(meshHit){++rayHits;++hitsByElevation[elevationIndex];continue;} if(!profileCrossing||!profileRoof)++missesNoProfileRoof; else ++missesMesh; if(firstMisses.size()<8) { std::ostringstream message; message<<"view="<(rayCount-raysBeforeView), static_cast(rayHits-hitsBeforeView), rayCount>raysBeforeView?100.0*static_cast(rayHits-hitsBeforeView)/(rayCount-raysBeforeView):0.0); } std::printf("[WorldAssemblerFarCapCoverage] rays=%llu hits=%llu coverage_pct=%.3f profile_crossings=%llu profile_roof_crossings=%llu misses_no_profile_roof=%llu misses_mesh=%llu misses_clip_edge=%llu view_points=%zu\n", static_cast(rayCount),static_cast(rayHits), rayCount?100.0*static_cast(rayHits)/rayCount:0.0, static_cast(profileCrossings),static_cast(profileRoofCrossings), static_cast(missesNoProfileRoof),static_cast(missesMesh), static_cast(missesClipEdge),walkOrigins.size()); for(std::size_t i=0;i(raysByElevation[i]), static_cast(hitsByElevation[i])); for(const auto& miss:firstMisses)std::printf("[WorldAssemblerFarCapCoverageMiss] %s\n",miss.c_str()); const bool censusPassing=requested>0&&unexplainedEmptyBands==0&&culled==0; const bool agreementPassing=agreementCompared>=32&&maximumAgreementCm<=AgreementToleranceCm &&negativeControlDetected; const bool coveragePassing=rayCount>0&&rayHits==rayCount; std::printf("[WorldAssemblerFarCapAudit] census=%s agreement=%s coverage=%s status=%s\n", censusPassing?"PASS":"FAIL",agreementPassing?"PASS":"FAIL", coveragePassing?"PASS":"FAIL",censusPassing&&agreementPassing&&coveragePassing?"PASS":"FAIL"); return censusPassing&&agreementPassing&&coveragePassing; } int RunWorldAssemblerAudit(FStandaloneOwnerWorld& owner, const VoxelForgeCore::ResolvedWorldSnapshot& snapshot,const std::string& captureDirectory, VoxelForgeCore::World* compiledWorld,VoxelForgeCore::Vec3d walkCameraVoxels) { const auto* manifest=snapshot.worldAssembly(); if(!manifest||manifest->plan.strates.empty()) {std::fprintf(stderr,"[WorldAssemblerAudit] no shipped world_assembly payload was resolved.\n");return 10;} const auto& plan=manifest->plan.strates.front(); const VoxelForgeCore::Heightfield2D block(manifest->recipe,plan); if(!block.isValid()) {std::fprintf(stderr,"[WorldAssemblerAudit] Heightfield2D rejected its recipe or plan.\n");return 10;} const auto contract=block.contract(); const auto influence=block.influenceBounds(); const auto detail=block.detailEnvelope(); const auto bounds=VoxelForgeCore::AuditHeightfieldBounds(block,256, 0x574f524c44415331ull^manifest->contentHash); std::printf("[WorldAssemblerBlock] name=Heightfield2D evaluator=%u reads=biome writes=height,rock influence_xy=global influence_z_q=%lld..%lld detail_envelope_q=%lld minimum_feature_q=%lld status=%s\n", contract.evaluatorVersion,static_cast(influence.minimumZSubvoxels), static_cast(influence.maximumZSubvoxels), static_cast(detail.maximumAbsoluteDisplacementSubvoxels), static_cast(detail.minimumFeatureSizeSubvoxels),bounds.passed?"PASS":"FAIL"); std::printf("[WorldAssemblerBoundAudit] boxes=%llu point_samples=%llu missed_bounds=%llu unknown_bounds=%llu border_boxes=%llu cliff_boxes=%llu cap_boxes=%llu negative_coordinate_boxes=%llu exception_boxes=%llu exception_point_samples=%llu deliberately_wrong_bound_detected=%s status=%s\n", static_cast(bounds.boxesTested), static_cast(bounds.pointSamples), static_cast(bounds.missedBounds), static_cast(bounds.unknownBounds), static_cast(bounds.biomeBorderBoxes), static_cast(bounds.cliffBoxes), static_cast(bounds.capBoxes), static_cast(bounds.negativeCoordinateBoxes), static_cast(bounds.exceptionBoxes), static_cast(bounds.exceptionPointSamples), bounds.negativeControlDetected?"true":"false",bounds.passed?"PASS":"FAIL"); const auto shelfThickness=VoxelForgeCore::AuditHeightfieldShelfThickness(block); std::printf("[WorldAssemblerShelfThicknessAudit] features=%llu columns=%llu active_columns=%llu negative_runs=%llu minimum_observed_vox=%.3f sub_voxel_runs=%llu sub_voxel_columns=%llu legacy_sub_voxel_runs=%llu legacy_sub_voxel_control_columns=%llu negative_control_detected=%s status=%s\n", static_cast(shelfThickness.featuresTested), static_cast(shelfThickness.columnsTested), static_cast(shelfThickness.activeColumns), static_cast(shelfThickness.negativeRuns), static_cast(shelfThickness.minimumObservedThicknessSubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel, static_cast(shelfThickness.subVoxelRuns), static_cast(shelfThickness.subVoxelColumns), static_cast(shelfThickness.legacySubVoxelRuns), static_cast(shelfThickness.legacySubVoxelColumns), shelfThickness.negativeControlDetected?"true":"false", shelfThickness.passed?"PASS":"FAIL"); std::printf("[WorldAssemblerShelfMinimumColumn] x_vox=%.3f y_vox=%.3f ground_z_vox=%.3f run_bottom_z_vox=%.3f run_top_z_vox=%.3f\n", static_cast(shelfThickness.minimumThicknessColumnXSubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel, static_cast(shelfThickness.minimumThicknessColumnYSubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel, static_cast(shelfThickness.minimumThicknessGroundSubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel, static_cast(shelfThickness.minimumThicknessBottomSubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel, static_cast(shelfThickness.minimumThicknessTopSubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel); const auto routeAudit=VoxelForgeCore::AuditHeightfieldRoute(block); auto raisedRoutePlan=plan; for(auto& point:raisedRoutePlan.route) point.positionSubvoxels[2]+=16*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const VoxelForgeCore::Heightfield2D raisedRouteBlock(manifest->recipe,raisedRoutePlan); const auto raisedRouteAudit=VoxelForgeCore::AuditHeightfieldRoute(raisedRouteBlock); const bool routeSupportNegativeControl=!raisedRouteAudit.passed &&raisedRouteAudit.unsupportedCenterSamples>0; std::printf("[WorldAssemblerRouteSweep] points=%zu segments=%llu swept_centers=%llu capsule_field_samples=%llu blocked_samples=%llu support_probes=%llu unsupported_centers=%llu grade_failures=%llu minimum_clearance_q=%lld maximum_support_depth_q=%lld unsupported_control_centers=%llu negative_control_detected=%s collision_readiness=%s status=%s\n", plan.route.size(),static_cast(routeAudit.segmentsTested), static_cast(routeAudit.centerSamples), static_cast(routeAudit.capsuleFieldSamples), static_cast(routeAudit.blockedCapsuleSamples), static_cast(routeAudit.supportProbeSamples), static_cast(routeAudit.unsupportedCenterSamples), static_cast(routeAudit.gradeFailures), static_cast(routeAudit.minimumClearanceSubvoxels), static_cast(routeAudit.maximumSupportDepthSubvoxels), static_cast(raisedRouteAudit.unsupportedCenterSamples), routeSupportNegativeControl?"true":"false", routeAudit.passed?"analytic_field_sweep_ready":"blocked", routeAudit.passed&&routeSupportNegativeControl?"PASS":"FAIL"); bool cliffRegressionPassing=false; const auto cliffIt=std::find_if(plan.features.begin(),plan.features.end(), [](const auto& feature){return feature.type==4;}); if(cliffIt!=plan.features.end()) { const std::size_t cliffIndex=static_cast(cliffIt-plan.features.begin()); auto basePlan=plan;basePlan.features.erase(basePlan.features.begin()+cliffIndex); auto boxControlPlan=plan;boxControlPlan.features[cliffIndex].type=2; const VoxelForgeCore::Heightfield2D baseBlock(manifest->recipe,basePlan); const VoxelForgeCore::Heightfield2D boxControlBlock(manifest->recipe,boxControlPlan); const auto& feature=*cliffIt; const std::int64_t cx=(feature.minimumSubvoxels[0]+feature.maximumSubvoxels[0])/2; const std::int64_t cy=(feature.minimumSubvoxels[1]+feature.maximumSubvoxels[1])/2; const std::int64_t z=feature.maximumSubvoxels[2] -VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; std::uint64_t airSamples=0,controlSlabSamples=0,taperedTopSamples=0; for(int gy=-2;gy<=2;++gy) for(int gx=-2;gx<=2;++gx) { const std::int64_t x=cx+gx*8*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const std::int64_t y=cy+gy*8*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const auto base=baseBlock.point(x,y,z); const auto control=boxControlBlock.point(x,y,z); const auto tapered=block.point(x,y,z); if(base.densitySubvoxels>0) { ++airSamples; if(control.densitySubvoxels<0)++controlSlabSamples; if(tapered.densitySubvoxels<0)++taperedTopSamples; } } const bool negativeControl=airSamples>=8&&controlSlabSamples==airSamples; cliffRegressionPassing=negativeControl&&taperedTopSamples*2(z),static_cast(airSamples), static_cast(controlSlabSamples), static_cast(taperedTopSamples), negativeControl?"true":"false",cliffRegressionPassing?"PASS":"FAIL"); } else std::printf("[WorldAssemblerCliffShapeAudit] type4_shelf=missing status=FAIL\n"); std::uint64_t seamBoxes=0,seamLatticeSamples=0,seamClassificationFailures=0; for(int boundaryY=-64;boundaryY<=64;boundaryY+=32) for(int boundaryX=-64;boundaryX<=64;boundaryX+=32) { const std::int64_t minX=static_cast(boundaryX-8) *VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const std::int64_t maxX=static_cast(boundaryX+8) *VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const std::int64_t minY=static_cast(boundaryY-8) *VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const std::int64_t maxY=static_cast(boundaryY+8) *VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; std::int64_t groundMin=std::numeric_limits::max(); std::int64_t groundMax=std::numeric_limits::min(); std::int64_t capMin=std::numeric_limits::max(); for(std::int64_t y=minY;y<=maxY;y+=8*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel) for(std::int64_t x=minX;x<=maxX;x+=8*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel) { const auto column=block.point(x,y,0); groundMin=std::min(groundMin,column.groundHeightSubvoxels); groundMax=std::max(groundMax,column.groundHeightSubvoxels); capMin=std::min(capMin,column.capHeightSubvoxels); } for(const bool bAir:{true,false}) { const std::int64_t minZ=bAir?groundMax+16*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel :groundMin-24*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const std::int64_t maxZ=bAir?minZ+8*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel :minZ+8*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; if(bAir&&maxZ>=capMin)continue; const auto verdict=block.classifyLatticeBox(minX,minY,minZ,maxX,maxY,maxZ,8); const auto expected=bAir?VoxelForgeCore::HeightfieldBoxClass::allAir :VoxelForgeCore::HeightfieldBoxClass::allSolid; ++seamBoxes; if(verdict!=expected){++seamClassificationFailures;continue;} for(std::int64_t zq=minZ;zq<=maxZ;zq+=8*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel) for(std::int64_t y=minY;y<=maxY;y+=8*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel) for(std::int64_t x=minX;x<=maxX;x+=8*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel) { const auto sample=block.point(x,y,zq); if((bAir&&sample.densitySubvoxels<=0)||(!bAir&&sample.densitySubvoxels>=0)) ++seamClassificationFailures; ++seamLatticeSamples; } } } const bool seamClassificationPassing=seamBoxes>0&&seamClassificationFailures==0 &&seamLatticeSamples>0; std::printf("[WorldAssemblerTileSeamAudit] boxes=%llu lattice_samples=%llu false_classifications=%llu seam_spacing_vox=32 box_span_vox=16 status=%s\n", static_cast(seamBoxes), static_cast(seamLatticeSamples), static_cast(seamClassificationFailures), seamClassificationPassing?"PASS":"FAIL"); struct Query {std::int64_t x=0,y=0,z=0;}; constexpr int side=64; std::vector queries; queries.reserve(side*side); for(int y=0;y(x)-side/2)*128 *VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const std::int64_t yq=(static_cast(y)-side/2)*128 *VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const auto column=block.point(xq,yq,0); const std::int64_t offset=(static_cast((x+3*y)%9)-4) *VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; queries.push_back({xq,yq,column.groundHeightSubvoxels+offset}); } std::vector oneWorker(queries.size()); const auto evaluate=[&](std::uint32_t workers, std::vector& output) { const auto begin=std::chrono::steady_clock::now(); std::vector threads; for(std::uint32_t worker=0;worker( std::chrono::steady_clock::now()-begin).count(); }; const auto hashSamples=[](const std::vector& samples) { std::uint64_t hash=14695981039346656037ull; const auto add=[&](std::uint64_t value,int bytes) { for(int i=0;i(value>>(8*i));hash*=1099511628211ull;} }; for(const auto& sample:samples) { add(static_cast(sample.groundHeightSubvoxels),8); add(static_cast(sample.capHeightSubvoxels),8); add(sample.biomeId,4);add(sample.neighborBiomeId,4);add(sample.biomeWeightQ16,4); add(static_cast(sample.densitySubvoxels),8); add(static_cast(sample.waterSurfaceSubvoxels),8); add(static_cast(sample.waterFillSubvoxels),8); } return hash; }; const double time1=evaluate(1,oneWorker); const std::uint64_t hash1=hashSamples(oneWorker); std::vector eightWorkers(queries.size()); const double time8=evaluate(8,eightWorkers); const std::uint64_t hash8=hashSamples(eightWorkers); std::vector sixteenWorkers(queries.size()); const double time16=evaluate(16,sixteenWorkers); const std::uint64_t hash16=hashSamples(sixteenWorkers); const bool deterministic=hash1==hash8&&hash1==hash16; std::printf("[WorldAssemblerEvaluatorHash] samples=%zu W1=%016llx W8=%016llx W16=%016llx deterministic=%s\n", queries.size(),static_cast(hash1), static_cast(hash8),static_cast(hash16), deterministic?"true":"false"); std::printf("[WorldAssemblerQueryTiming] samples=%zu native_W1_ms=%.3f native_W8_ms=%.3f native_W16_ms=%.3f scope=point_evaluation_only\n", queries.size(),time1,time8,time16); double ownerHeightSum=0.0,nativeHeightSum=0.0; double ownerHeightSquareSum=0.0,nativeHeightSquareSum=0.0,centeredCrossSum=0.0; double heightAbsoluteSum=0.0,heightMaximumError=0.0; std::vector heightDeltas; heightDeltas.reserve(4096); std::uint64_t ownerBiomeSamples=0,ownerBiomeIdMismatches=0; const FBiomeContext ownerBiomeContext=owner.Manager->GetBiomeContextForChunk( FIntVector(0,0,plan.topChunkZ)); std::uint64_t heightSamples=0; constexpr int heightProbeSide=64; constexpr double heightProbeSpan=3200.0; for(int y=0;y(x)/(heightProbeSide-1)-0.5)*heightProbeSpan; const double yVoxel=(static_cast(y)/(heightProbeSide-1)-0.5)*heightProbeSpan; float ownerGround=0.0f,ownerCap=0.0f; if(!owner.Generator->GetSurfaceHeightAt(static_cast(xVoxel), static_cast(yVoxel),plan.topChunkZ,ownerGround,ownerCap))continue; const auto native=block.point( static_cast(std::llround(xVoxel*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)), static_cast(std::llround(yVoxel*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)),0); const double nativeGround=static_cast(native.groundHeightSubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const double ownerGroundValue=ownerGround; ownerHeightSum+=ownerGroundValue;nativeHeightSum+=nativeGround; ownerHeightSquareSum+=ownerGroundValue*ownerGroundValue; nativeHeightSquareSum+=nativeGround*nativeGround; centeredCrossSum+=ownerGroundValue*nativeGround; const double difference=std::abs(nativeGround-ownerGroundValue); heightAbsoluteSum+=difference;heightMaximumError=std::max(heightMaximumError,difference); heightDeltas.push_back(nativeGround-ownerGroundValue); FVoxelBiomeQuery ownerBiome; owner.Generator->QueryBiomeAt(static_cast(xVoxel),static_cast(yVoxel), plan.topChunkZ,ownerBiome); if(ownerBiome.bHasBiomes&&ownerBiomeContext.Biomes.IsValidIndex(ownerBiome.DominantContextIndex)) { const std::uint32_t ownerBiomeId=0x1001u+static_cast( ownerBiomeContext.Biomes[ownerBiome.DominantContextIndex].Index); ++ownerBiomeSamples; if(native.biomeId!=ownerBiomeId)++ownerBiomeIdMismatches; } ++heightSamples; } if(heightSamples>0) { const double ownerMean=ownerHeightSum/heightSamples; const double nativeMean=nativeHeightSum/heightSamples; const double ownerVariance=std::max(0.0,ownerHeightSquareSum/heightSamples-ownerMean*ownerMean); const double nativeVariance=std::max(0.0,nativeHeightSquareSum/heightSamples-nativeMean*nativeMean); const double covariance=centeredCrossSum/heightSamples-ownerMean*nativeMean; const double slope=ownerVariance>0.0?covariance/ownerVariance:0.0; const double intercept=nativeMean-slope*ownerMean; const double correlation=(ownerVariance>0.0&&nativeVariance>0.0) ?covariance/std::sqrt(ownerVariance*nativeVariance):0.0; double offsetCorrectedAbsoluteSum=0.0; for(const double delta:heightDeltas)offsetCorrectedAbsoluteSum+=std::abs(delta-(nativeMean-ownerMean)); std::printf("[WorldAssemblerSurfaceShapeDiagnostic] samples=%llu owner_voxel_cm=%.1f core_voxel_cm=%.1f mean_owner_height=%.3f mean_native_height=%.3f mean_offset=%.3f mae=%.3f mae_after_mean_offset_removal=%.3f max_error=%.3f regression_native_equals_slope_owner_plus_offset_slope=%.5f offset=%.3f correlation=%.5f owner_biome_samples=%llu owner_biome_id_mismatches=%llu\n", static_cast(heightSamples),VOXEL_SIZE,25.0, ownerMean,nativeMean,nativeMean-ownerMean,heightAbsoluteSum/heightSamples, heightDeltas.empty()?0.0:offsetCorrectedAbsoluteSum/heightDeltas.size(), heightMaximumError,slope,intercept,correlation, static_cast(ownerBiomeSamples), static_cast(ownerBiomeIdMismatches)); } struct FWorldAssemblerCaptureSite {double X=0.0,Y=0.0,OwnerGround=0.0,NativeGround=0.0,Score=0.0;bool Found=false;}; FWorldAssemblerCaptureSite borderSite,coastSite; const auto waterVoxel=static_cast(plan.waterSurfaceSubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; for(int y=-1600;y<=1600;y+=64) for(int x=-1600;x<=1600;x+=64) { float ownerGround=0.0f,ownerCap=0.0f; if(!owner.Generator->GetSurfaceHeightAt(static_cast(x),static_cast(y), plan.topChunkZ,ownerGround,ownerCap))continue; FVoxelBiomeQuery ownerBiome; owner.Generator->QueryBiomeAt(static_cast(x),static_cast(y), plan.topChunkZ,ownerBiome); const auto native=block.point(static_cast(x) *VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel,static_cast(y) *VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel,0); if(ownerBiome.bHasBiomes&&ownerBiome.NeighborWeight>borderSite.Score) borderSite={static_cast(x),static_cast(y),ownerGround, static_cast(native.groundHeightSubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel, ownerBiome.NeighborWeight,true}; const double waterDistance=std::abs(static_cast(ownerGround)-waterVoxel); if(!coastSite.Found||waterDistance(x),static_cast(y),ownerGround, static_cast(native.groundHeightSubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel, waterDistance,true}; } const auto printCaptureSite=[&](const char* name,const FWorldAssemblerCaptureSite& site) { if(!site.Found)return; const double cameraX=site.X/4.0,cameraY=(site.Y-140.0)/4.0; const double cameraZ=(site.OwnerGround+64.0)/4.0; std::printf("[WorldAssemblerCaptureSite] name=%s target_vox=(%.0f,%.0f,%.2f) owner_ground_vox=%.2f native_ground_vox=%.2f score=%.5f camera_m=(%.3f,%.3f,%.3f,0,-22)\n", name,site.X,site.Y,site.OwnerGround,site.OwnerGround,site.NativeGround,site.Score, cameraX,cameraY,cameraZ); }; const auto originNativeColumn=block.point(0,0,0); float originOwnerGround=0.0f,originOwnerCap=0.0f; if(owner.Generator->GetSurfaceHeightAt(0.0f,0.0f,plan.topChunkZ, originOwnerGround,originOwnerCap)) printCaptureSite("surface",{0.0,0.0,originOwnerGround, static_cast(originNativeColumn.groundHeightSubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel,0.0,true}); printCaptureSite("biome_border",borderSite); printCaptureSite("coast",coastSite); if(!plan.features.empty()&&(plan.features.front().type==2||plan.features.front().type==4)) { const auto& feature=plan.features.front(); const double fx=(feature.minimumSubvoxels[0]+feature.maximumSubvoxels[0]) /(2.0*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel); const double fy=(feature.minimumSubvoxels[1]+feature.maximumSubvoxels[1]) /(2.0*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel); float ownerGround=0.0f,ownerCap=0.0f; if(owner.Generator->GetSurfaceHeightAt(static_cast(fx),static_cast(fy), plan.topChunkZ,ownerGround,ownerCap)) { const auto native=block.point(static_cast(std::llround(fx *VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)),static_cast(std::llround(fy *VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)),0); printCaptureSite("cliff",{fx,fy,ownerGround, static_cast(native.groundHeightSubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel,0.0,true}); } } double absoluteSum=0.0,maximumError=0.0; std::uint64_t signMismatches=0; const auto legacyStart=std::chrono::steady_clock::now(); for(std::size_t i=0;i(queries[i].x /static_cast(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)); const float y=static_cast(queries[i].y /static_cast(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)); const float z=static_cast(queries[i].z /static_cast(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)); const float legacyDensity=owner.Generator->GetDensityAt(x,y,z); const double error=std::abs(static_cast(oneWorker[i].densitySubvoxels /static_cast(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel))-legacyDensity); absoluteSum+=error;maximumError=std::max(maximumError,error); if((oneWorker[i].densitySubvoxels<0)!=(legacyDensity<0.0f)) ++signMismatches; } const double legacyMs=std::chrono::duration( std::chrono::steady_clock::now()-legacyStart).count(); std::printf("[WorldAssemblerLegacyCompare] samples=%zu mean_abs_density_error=%.4f max_abs_density_error=%.4f sign_mismatches=%llu legacy_point_queries_ms=%.3f status=MEASURED_NOT_PARITY_GATE\n", queries.size(),absoluteSum/queries.size(),maximumError, static_cast(signMismatches),legacyMs); const auto centerColumn=block.point(0,0,0); const int32 centerGroundVoxel=static_cast(std::llround( static_cast(centerColumn.groundHeightSubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)); VoxelForgeCore::World coreWorld(snapshot); VoxelForgeCore::ShapeBuildRequest coreBuild; coreBuild.minVoxel={-32,-32,centerGroundVoxel-32}; coreBuild.maxVoxel={32,32,centerGroundVoxel+32}; coreBuild.clipMinVoxel=coreBuild.minVoxel; coreBuild.clipMaxVoxel=coreBuild.maxVoxel; coreBuild.workerLimit=1; coreBuild.validatePassageRoutes=false; FStandaloneCoreScheduler scheduler; std::string coreError; const auto coreCompileStart=std::chrono::steady_clock::now(); const bool coreCompiled=coreWorld.compile(coreBuild,scheduler,coreError); const double coreCompileMs=std::chrono::duration( std::chrono::steady_clock::now()-coreCompileStart).count(); double coreQueryMaximumError=0.0; std::uint64_t coreQuerySamples=0; if(coreCompiled) { for(const std::int64_t dx:{-24ll,0ll,24ll}) for(const std::int64_t dy:{-24ll,0ll,24ll}) for(const std::int64_t dz:{-8ll,-1ll,0ll,1ll,8ll}) { const std::int64_t xq=dx*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const std::int64_t yq=dy*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const std::int64_t zq=centerColumn.groundHeightSubvoxels +dz*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const double expected=static_cast(block.point(xq,yq,zq).densitySubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const double actual=coreWorld.densityAt({static_cast(xq) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel, static_cast(yq)/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel, static_cast(zq)/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel}); coreQueryMaximumError=std::max(coreQueryMaximumError,std::abs(expected-actual)); ++coreQuerySamples; } for(const auto& routePoint:plan.route) { const auto& position=routePoint.positionSubvoxels; const double x=static_cast(position[0])/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const double y=static_cast(position[1])/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const double z=static_cast(position[2])/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const double expected=static_cast(block.point(position[0],position[1],position[2]) .densitySubvoxels)/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; const double actual=coreWorld.densityAt({x,y,z}); coreQueryMaximumError=std::max(coreQueryMaximumError,std::abs(expected-actual)); ++coreQuerySamples; } } const std::uint64_t expectedCoreQuerySamples=45+plan.route.size(); const bool coreQueryPass=coreCompiled&&coreQuerySamples==expectedCoreQuerySamples &&coreQueryMaximumError<=1.0/256.0; std::printf("[WorldAssemblerServerFieldQuery] role=server_api_path=World::densityAt compiled=%s compile_ms=%.3f samples=%llu route_waypoints=%zu max_abs_error=%.8f render_meshes_generated=0 local_field_query=%s collision_mesh_cooking=not_in_standalone_core status=%s error=%s\n", coreCompiled?"true":"false",coreCompileMs, static_cast(coreQuerySamples),plan.route.size(),coreQueryMaximumError, coreQueryPass?"ready_without_meshes":"unavailable",coreQueryPass?"PASS":"FAIL", coreError.empty()?"none":coreError.c_str()); if(!captureDirectory.empty()) { constexpr int width=320,height=200; constexpr double spanVoxels=3200.0; const std::size_t columnCount=static_cast(width)*height; std::vector ownerPixels(columnCount*3,0); std::vector nativePixels(ownerPixels.size(),0); std::vector ownerHeights(columnCount,std::numeric_limits::quiet_NaN()); std::vector nativeHeights(columnCount,0.0); double minimumHeight=std::numeric_limits::max(); double maximumHeight=std::numeric_limits::lowest(); std::uint64_t ownerColumns=0; for(int y=0;y(x)/(width-1)-0.5)*spanVoxels; const double yVoxel=(static_cast(y)/(height-1)-0.5)*spanVoxels; const std::size_t column=static_cast(y)*width+x; float ownerGround=0.0f,ownerCap=0.0f; if(owner.Generator->GetSurfaceHeightAt(static_cast(xVoxel), static_cast(yVoxel),plan.topChunkZ,ownerGround,ownerCap)) { if(std::isfinite(ownerGround)) { ownerHeights[column]=ownerGround; minimumHeight=std::min(minimumHeight,static_cast(ownerGround)); maximumHeight=std::max(maximumHeight,static_cast(ownerGround)); ++ownerColumns; } } const auto native=block.point( static_cast(std::llround(xVoxel*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)), static_cast(std::llround(yVoxel*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)),0); nativeHeights[column]=static_cast(native.groundHeightSubvoxels) /VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel; minimumHeight=std::min(minimumHeight,nativeHeights[column]); maximumHeight=std::max(maximumHeight,nativeHeights[column]); } const auto colorHeight=[&](double heightValue,std::vector& pixels,std::size_t offset) { const double t=std::clamp((heightValue-minimumHeight) /std::max(1.0,maximumHeight-minimumHeight),0.0,1.0); const std::array,4> stops={{{24,68,78},{61,128,75}, {166,143,83},{232,229,209}}}; const double scaled=t*3.0; const int segment=std::min(2,static_cast(scaled)); const double blend=scaled-segment; for(int channel=0;channel<3;++channel) pixels[offset+channel]=static_cast(std::clamp(std::lround( stops[segment][channel]*(1.0-blend)+stops[segment+1][channel]*blend),0l,255l)); }; for(std::size_t column=0;column& pixels) { std::ofstream output(path,std::ios::binary); if(!output)return false; output<<"P6\n"<(pixels.data()), static_cast(pixels.size())); return static_cast(output); }; const bool ownerSaved=!directoryError&&writePpm( std::filesystem::path(captureDirectory)/"owner-reference-height.ppm",ownerPixels); const bool nativeSaved=!directoryError&&writePpm( std::filesystem::path(captureDirectory)/"native-prototype-height.ppm",nativePixels); std::printf("[WorldAssemblerCapturePair] resolution=%dx%d xy_span_vox=%.0f height_range=[%.2f,%.2f] owner_columns=%llu owner_saved=%s native_saved=%s files=owner-reference-height.ppm,native-prototype-height.ppm status=%s\n", width,height,spanVoxels,minimumHeight,maximumHeight,static_cast(ownerColumns), ownerSaved?"true":"false",nativeSaved?"true":"false", ownerSaved&&nativeSaved?"PASS":"FAIL"); } std::printf("[WorldAssemblerFullViewTiming] status=NOT_MEASURED_IN_AUDIT_MODE; capture_viewer_runs_report_separately\n"); std::printf("[WorldAssemblerReadiness] local_field_query=%s analytic_collision_validation=%s physics_collision_cooking=deferred_to_Unreal_adapter render_mesh_readiness=reported_by_matched_view_runs\n", coreQueryPass?"ready_without_render_meshes":"not_ready", routeAudit.passed?"route_sweep_ready":"not_ready"); const bool farCapAuditPassing=compiledWorld!=nullptr &&RunWorldAssemblerCapAudit(owner,snapshot,*compiledWorld,walkCameraVoxels); return bounds.passed&&shelfThickness.passed&&routeAudit.passed &&routeSupportNegativeControl&&cliffRegressionPassing&&seamClassificationPassing &&deterministic&&coreQueryPass&&farCapAuditPassing?0:11; } } int main(int Argc,char** Argv) { DWORD_PTR ProcessAffinity=0,SystemAffinity=0; if(!GetProcessAffinityMask(GetCurrentProcess(),&ProcessAffinity,&SystemAffinity)) { std::fprintf(stderr,"[ProcessControlsError] GetProcessAffinityMask failed.\n"); return 2; } DWORD_PTR RequestedAffinity=0; DWORD RequestedPriority=0; const char* AffinitySource="inherited"; const char* PrioritySource="inherited"; for(int32 I=1;I(Parsed); AffinitySource="argument"; } else if(Arg.starts_with("--process-priority=")) { const std::string_view Value=Arg.substr(std::string_view("--process-priority=").size()); if(Value=="Normal")RequestedPriority=NORMAL_PRIORITY_CLASS; else if(Value=="BelowNormal")RequestedPriority=BELOW_NORMAL_PRIORITY_CLASS; else { std::fprintf(stderr,"[ProcessControlsError] invalid --process-priority value: %.*s\n", static_cast(Value.size()),Value.data()); return 2; } PrioritySource="argument"; } } bool bAffinitySet=true,bPrioritySet=true; if(RequestedAffinity!=0) { if((RequestedAffinity&~SystemAffinity)!=0) { std::fprintf(stderr,"[ProcessControlsError] requested affinity mask is outside system mask 0x%llX.\n", static_cast(SystemAffinity)); return 2; } bAffinitySet=SetProcessAffinityMask(GetCurrentProcess(),RequestedAffinity)!=0; } if(RequestedPriority!=0) bPrioritySet=SetPriorityClass(GetCurrentProcess(),RequestedPriority)!=0; if(!bAffinitySet||!bPrioritySet) { std::fprintf(stderr,"[ProcessControlsError] failed to apply requested process controls.\n"); return 2; } if(!GetProcessAffinityMask(GetCurrentProcess(),&ProcessAffinity,&SystemAffinity)) { std::fprintf(stderr,"[ProcessControlsError] could not read applied process affinity.\n"); return 2; } const DWORD AppliedPriority=GetPriorityClass(GetCurrentProcess()); const char* PriorityName=AppliedPriority==NORMAL_PRIORITY_CLASS?"Normal": (AppliedPriority==BELOW_NORMAL_PRIORITY_CLASS?"BelowNormal": (AppliedPriority==ABOVE_NORMAL_PRIORITY_CLASS?"AboveNormal": (AppliedPriority==HIGH_PRIORITY_CLASS?"High": (AppliedPriority==REALTIME_PRIORITY_CLASS?"Realtime":"Unknown")))); std::printf("[ProcessControls] priority_class=%s priority_source=%s affinity_mask=0x%llX affinity_source=%s requested_affinity=0x%llX system_affinity=0x%llX\n", PriorityName,PrioritySource,static_cast(ProcessAffinity),AffinitySource, static_cast(RequestedAffinity),static_cast(SystemAffinity)); const auto ColdProcessStart=std::chrono::steady_clock::now(); FApp App;App.DataPath=DefaultDataPath().string();App.ColdProcessStart=ColdProcessStart; wchar_t ExecutablePath[MAX_PATH]{}; const DWORD ExecutablePathLength=GetModuleFileNameW(nullptr,ExecutablePath,MAX_PATH); if(ExecutablePathLength>0&&ExecutablePathLength(Value.size()),Value.data());return 2;} } else if(Arg=="--round-tunnels")App.bRoundTunnels=true; else if(Arg=="--round-tunnels-legacy") {App.bRoundTunnels=true;App.bRoundTunnelEnhanced=false;} else if(Arg=="--stream-benchmark")bStreamBenchmark=true; else if(Arg=="--stream-pipeline") {bStreamPipeline=true;bStreamBenchmark=true;App.bShapeWorld=true;App.bForceGenerate=true;} else if(Arg=="--edit-benchmark") {bEditBenchmark=true;bStreamBenchmark=true;App.bShapeWorld=true;} else if(Arg=="--stream-hash")bStreamHash=true; else if(Arg=="--skip-uv-colors")bSkipUvAndColors=true; else if(Arg=="--skip-uv")bSkipUV=true; else if(Arg=="--skip-colors")bSkipColors=true; else if(Arg=="--skip-material-groups")bSkipMaterialGroups=true; else if(Arg=="--shard-audit")bShardAudit=true; else if(Arg=="--far-survival-audit")bFarSurvivalAudit=true,App.bShapeWorld=true; else if(Arg=="--far-audit-bad-shell") {bFarAuditBadShell=true;bFarSurvivalAudit=true;App.bShapeWorld=true;} else if(Arg=="--compare-round-walls") {bRoundWallCompare=true;App.bRoundTunnels=true;} else if(Arg.starts_with("--round-compare-tiles=")) RoundCompareTileCount=std::max(1,std::atoi(std::string(Arg.substr(22)).c_str())); else if(Arg=="--force-generate")App.bForceGenerate=true; else if(Arg.starts_with("--bake-mesh-cache=")) {BakeMeshCachePath=std::string(Arg.substr(18));App.bForceGenerate=true;} else if(Arg.starts_with("--stream-max-level=")) StreamBenchmarkMaxLevel=std::atoi(std::string(Arg.substr(19)).c_str()); else if(Arg.starts_with("--max-clip-level=")) MaxClipLevelOverride=std::clamp( std::atoi(std::string(Arg.substr(17)).c_str()),0,8); else if(Arg=="--test-one-chunk-crossing") { App.FlightTargetCrossings=1; App.bShapeWorld=true; } else if(Arg.starts_with("--test-flight-crossings=")) { App.FlightTargetCrossings=std::max(1,std::atoi( std::string(Arg.substr(std::string_view("--test-flight-crossings=").size())).c_str())); App.bShapeWorld=true; } else if(Arg.starts_with("--flight-speed-mps=")) App.FlightSpeedMps=std::clamp(std::strtof( std::string(Arg.substr(std::string_view("--flight-speed-mps=").size())).c_str(),nullptr), 1.0f,256.0f); else if(Arg=="--capture-after-clipmap")App.bCaptureAfterClipmap=true; else if(Arg=="--quit-after-clipmap")App.bQuitAfterClipmap=true; else if(Arg.starts_with("--workers=")) { const int32 Parsed=std::atoi(std::string(Arg.substr(10)).c_str()); App.WorkerCount=std::clamp(Parsed,1,16); } else if(Arg.starts_with("--clip-radius=")) App.ClipRadius=std::clamp(std::atoi(std::string(Arg.substr(14)).c_str()),1,64); 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("--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())); else if(Arg.starts_with("--benchmark-level=")) BenchmarkLevel=std::atoi(std::string(Arg.substr(18)).c_str()); else if(Arg.starts_with("--benchmark-count=")) BenchmarkCount=std::max(1,std::atoi(std::string(Arg.substr(18)).c_str())); else if(Arg.starts_with("--camera=")) { const std::string Values(Arg.substr(9)); float X=0,Y=0,Z=0,YawDegrees=0,PitchDegrees=0; if(std::sscanf(Values.c_str(),"%f,%f,%f,%f,%f",&X,&Y,&Z,&YawDegrees,&PitchDegrees)==5) { App.bHasCameraOverride=true;App.CameraPositionOverride={X,Y,Z}; App.CameraYawOverride=YawDegrees*0.017453292519943295f; App.CameraPitchOverride=PitchDegrees*0.017453292519943295f; } else {std::fprintf(stderr,"Invalid --camera value: %s\n",Values.c_str());return 2;} } else if(!Arg.empty()&&Arg.front()!='-')App.DataPath=std::string(Arg); } std::printf("[FrameLimiter] target_fps=%d maximum=true vsync=%s source=%s\n",FrameLimitHz, App.bDisableVSync?"off":"on",bFrameLimitSpecified?"argument":"default"); 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; } if(App.bDisableGpuWarmupPresentHold)App.bHoldCpuFrameDuringGpuWarmup=false; App.bProfileDetailBand=bProfileDetailBand; std::string Error; std::printf("[ColdTimeline] stage=owner_data_load begin_ms=%.3f\n", std::chrono::duration(std::chrono::steady_clock::now()-ColdProcessStart).count()); App.World=std::make_shared(); { std::ifstream JsonFile(App.DataPath,std::ios::binary); if(!JsonFile){std::fprintf(stderr,"Owner data load failed: cannot open %s\n",App.DataPath.c_str());return 2;} std::string OwnerJsonText{std::istreambuf_iterator(JsonFile),std::istreambuf_iterator{}}; if(!JsonFile&& !JsonFile.eof()) {std::fprintf(stderr,"Owner data load failed: read error for %s\n",App.DataPath.c_str());return 2;} if(!VFJson::Parser(std::move(OwnerJsonText)).Parse(App.OwnerJsonRoot,Error)) {std::fprintf(stderr,"Owner data load failed: %s\n",Error.c_str());return 2;} } if(!StandaloneOwnerLoader::Resolve(App.OwnerJsonRoot,*App.World,Error)) {std::fprintf(stderr,"Owner data load failed: %s\n",Error.c_str());return 2;} std::printf("[ColdTimeline] stage=owner_data_load end_ms=%.3f\n", std::chrono::duration(std::chrono::steady_clock::now()-ColdProcessStart).count()); App.Seed=App.World->Seed; if(App.bParityOnly) { VoxelGenLOD::InitializeConsoleSwitches(); return App.PrintParity()==0?0:1; } App.Position={static_cast(App.World->ViewerStartVoxels.X*0.25), static_cast(App.World->ViewerStartVoxels.Y*0.25),static_cast(App.World->ViewerStartVoxels.Z*0.25)}; if(App.bHasCameraOverride){App.Position=App.CameraPositionOverride;App.Yaw=App.CameraYawOverride;App.Pitch=App.CameraPitchOverride;} const int32 ExportClipRadius=App.World->ClipRadius; const int32 ExportMaxClipLevel=App.World->MaxClipLevel; App.World->ClipRadius=App.ClipRadius; App.World->Settings->ClipRadius=App.ClipRadius; if(App.bRoundTunnels&&!PrepareStandaloneDensityWorld(*App.World,App.Seed, App.bRoundTunnels,App.bRoundTunnelEnhanced,Error)) {std::fprintf(stderr,"Standalone world setup failed: %s\n",Error.c_str());return 2;} if(MaxClipLevelOverride>=0) { App.MaxClipLevelOverride=MaxClipLevelOverride; App.World->MaxClipLevel=MaxClipLevelOverride; App.World->Settings->MaxClipLevel=MaxClipLevelOverride; std::printf("Standalone max clip level override: exported=%d -> max_level=%d.\n", ExportMaxClipLevel,MaxClipLevelOverride); } if(App.bWorldAssemblerPrototype) { const auto PlanStart=std::chrono::steady_clock::now(); const bool bPlanReady=AttachRound1WorldAssemblyPrototype(*App.World,App.OwnerJsonRoot, Error,WorldAssemblyManifestOutputPath); const double PlanMilliseconds=std::chrono::duration( std::chrono::steady_clock::now()-PlanStart).count(); std::printf("[WorldAssemblerPlanTiming] total_ms=%.3f status=%s\n", PlanMilliseconds,bPlanReady?"PASS":"FAIL"); if(!bPlanReady) {std::fprintf(stderr,"World assembler prototype setup failed: %s\n",Error.c_str());return 2;} } if(App.bWorldAssemblerAuditOnly) { App.Snapshot=VoxelForgeCore::MakeStandaloneSnapshotFromParsedJson(App.OwnerJsonRoot, App.Seed,App.ClipRadius,App.MaxClipLevelOverride,App.bRoundTunnels, App.bRoundTunnelEnhanced,Error); if(!App.Snapshot) {std::fprintf(stderr,"World assembler snapshot setup failed: %s\n",Error.c_str());return 2;} App.bShapeWorld=true; if(!App.BuildShapeWorldForCamera(Error,true,false,true)) {std::fprintf(stderr,"World assembler cap audit shape build failed: %s\n",Error.c_str());return 2;} return RunWorldAssemblerAudit(*App.World,App.Snapshot,WorldAssemblyCaptureDir, App.ShapeWorld.get(),{App.Position.X*4.0,App.Position.Y*4.0,App.Position.Z*4.0}); } const bool bNeedFarShapeWorld=bStreamBenchmark ?(StreamBenchmarkMaxLevel<0||StreamBenchmarkMaxLevel>=App.World->FullResClipLevels) :(App.bShapeCompare?ShapeCompareLevel>=App.World->FullResClipLevels :(BenchmarkLevel>=App.World->FullResClipLevels)); if(App.bShapeWorld&&(App.bShapeAuditOnly||App.bWalkabilityAuditOnly||bGridStairAudit||bTilePathHashAudit||App.bShapeCompare||bStreamBenchmark||BenchmarkLevel>=0) &&!bStreamPipeline &&!App.BuildShapeWorldForCamera(Error,bNeedFarShapeWorld)) {std::fprintf(stderr,"Shape interval build failed: %s\n",Error.c_str());return 2;} if(bStreamPipeline) { App.Snapshot=VoxelForgeCore::MakeStandaloneSnapshotFromParsedJson(App.OwnerJsonRoot, App.Seed,App.ClipRadius,App.MaxClipLevelOverride,App.bRoundTunnels, App.bRoundTunnelEnhanced,Error); if(!App.Snapshot) {std::fprintf(stderr,"Shape interval build failed: %s\n",Error.c_str());return 2;} } if(App.bWalkabilityAuditOnly)return 0; if(App.bShapeAuditOnly) { if(bPassageDetailAuditOnly) return App.ShapeWorld->auditSurfaceFamilies(true)?0:8; const bool bSurfacePassing=App.ShapeWorld->auditViewSurface( {App.Position.X*4.0,App.Position.Y*4.0,App.Position.Z*4.0}, App.Yaw,App.Pitch); return App.ShapeWorld->auditDetailPassing()&&bSurfacePassing?0:7; } if(bGridStairAudit) return App.ShapeWorld->auditGridStairIntegrity()?0:9; if(bTilePathHashAudit) return RunTilePathHashAudit(*App.ShapeWorld,App.Snapshot,App.CoreScheduler, FVector(App.Position.X*4.0,App.Position.Y*4.0,App.Position.Z*4.0), App.WorkerCount,App.ShapeDetailVariant,App.bRoundTunnels,App.bRoundTunnelEnhanced); if(App.bShapeCompare) return RunOwnerShapeComparison(*App.World,*App.ShapeWorld,App.Position,App.Yaw,App.Pitch,App.WorkerCount, ShapeCompareLevel,ShapeCompareTileLimit,ShapeCompareArea,bCheckOwnerReliefBands); if(bRoundWallCompare) return RunRoundWallComparison(*App.World,App.Position,RoundCompareTileCount); if(bStreamBenchmark) { if(bStreamPipeline) return RunPipelinedStreamingBenchmark(App.World,App.Snapshot, FVector(App.Position.X*4.0,App.Position.Y*4.0,App.Position.Z*4.0), App.WorkerCount,StreamBenchmarkMaxLevel,App.ShapeDetailVariant,App.CoreScheduler, bStreamHash||!BakeMeshCachePath.empty(),bSkipUvAndColors,bSkipMaterialGroups, bSkipUV,bSkipColors,ColdProcessStart); if(bEditBenchmark) return RunEditTransactionBenchmark(*App.World,*App.ShapeWorld, FVector(App.Position.X*4.0,App.Position.Y*4.0,App.Position.Z*4.0),App.WorkerCount); const double FullDetailWidth=static_cast(2*App.ClipRadius+2) *CHUNK_SIZE*VOXEL_SIZE/100.0; std::printf("Standalone clip override: exported radius=%d (112 m cube) -> radius=%d (%.0f m LOD0 cube), voxel size=25 cm.\n", ExportClipRadius,App.ClipRadius,FullDetailWidth); if(!App.bForceGenerate&&!App.bShapeWorld)App.LoadMeshCache(); return RunStreamingBenchmark(*App.World,App.ShapeWorld.get(), FVector(App.Position.X*4.0,App.Position.Y*4.0,App.Position.Z*4.0), App.WorkerCount,StreamBenchmarkMaxLevel,App.bRoundTunnels, App.bRoundTunnelEnhanced,(!App.bShapeWorld&&App.MeshCache.IsLoaded())?&App.MeshCache:nullptr, bStreamHash,bSkipUvAndColors,bSkipMaterialGroups,bSkipUV,bSkipColors,bShardAudit, bFarSurvivalAudit,bFarAuditBadShell,App.Yaw,App.Pitch, BakeMeshCachePath,App.MakeMeshCacheMetadata()); } if(BenchmarkLevel>=0) return RunTileBenchmark(*App.World,App.Position,BenchmarkLevel,BenchmarkCount, App.bProfileAttribution,App.bCompareEvaluators,App.bDensityHash,App.ShapeWorld.get()); App.World.reset(); WNDCLASSA Class{};Class.lpfnWndProc=WindowProc;Class.hInstance=GetModuleHandleA(nullptr);Class.lpszClassName="VoxelForgeStandaloneWorld"; Class.hCursor=LoadCursor(nullptr,IDC_ARROW);RegisterClassA(&Class); RECT Rect{0,0,App.Width,App.Height};AdjustWindowRect(&Rect,WS_OVERLAPPEDWINDOW,FALSE); App.Window=CreateWindowA(Class.lpszClassName,"VoxelForge standalone world",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT, Rect.right-Rect.left,Rect.bottom-Rect.top,nullptr,nullptr,Class.hInstance,nullptr); GApp=&App; const auto DeviceInitStart=std::chrono::steady_clock::now(); std::printf("[ColdTimeline] stage=viewer_device_init begin_ms=%.3f\n", std::chrono::duration(DeviceInitStart-ColdProcessStart).count()); if(!App.Window||!App.InitializeDevice()){MessageBoxA(nullptr,"Direct3D 11 initialization failed.","VoxelForge standalone",MB_ICONERROR);return 3;} std::printf("[ColdTimeline] stage=viewer_device_init end_ms=%.3f duration_ms=%.3f\n", std::chrono::duration(std::chrono::steady_clock::now()-ColdProcessStart).count(), std::chrono::duration(std::chrono::steady_clock::now()-DeviceInitStart).count()); App.StartGpuWarmupPolicyResolutionAsync(); if(!App.bGpuFarWarmupOnly) { const auto WindowShowStart=std::chrono::steady_clock::now(); ShowWindow(App.Window,SW_SHOW); if(!App.CapturePath.empty()) { BringWindowToTop(App.Window); SetForegroundWindow(App.Window); } std::printf("[ColdTimeline] stage=viewer_window_show duration_ms=%.3f\n", std::chrono::duration( std::chrono::steady_clock::now()-WindowShowStart).count()); const auto WindowUpdateStart=std::chrono::steady_clock::now(); UpdateWindow(App.Window); std::printf("[ColdTimeline] stage=viewer_window_update duration_ms=%.3f\n", std::chrono::duration( std::chrono::steady_clock::now()-WindowUpdateStart).count()); const auto StartupBannerStart=std::chrono::steady_clock::now(); std::printf("Controls: hold right mouse to look; WASD move; Space/Ctrl (E/Q) up/down; Shift faster; wheel changes speed; F wireframe; G toggles legacy/detailed round walls; H toggles CPU/GPU far tiles; 1-9 toggle LOD; 0 toggle all levels; N/P change seed; T swaps base/round tunnels; V swaps owner density/shape intervals; Esc quit.\n"); std::printf("Owner data: %s; starting at first-strate open-space sample (%.2f, %.2f, %.2f) m.\n", App.DataPath.c_str(),App.Position.X,App.Position.Y,App.Position.Z); std::printf("[ColdTimeline] stage=viewer_startup_banner duration_ms=%.3f\n", std::chrono::duration( std::chrono::steady_clock::now()-StartupBannerStart).count()); } if(App.bGpuFarEnabled&&(App.bGpuFarWarmupOnly||App.bGpuFarWarmupBeforeWorkers)) { App.ResolveGpuWarmupLaunchPolicy(true); std::string GpuInitError; if(!App.EnsureGpuFarPipeline(GpuInitError))return 3; } if(App.bGpuFarWarmupOnly) { const auto WarmupOnlyStart=std::chrono::steady_clock::now(); std::string WarmupError; if(!VoxelForgeGpuFarViewer::QueueFarShaderWarmup(App.Device,App.Context,App.GpuFarShaderPath, true,App.GpuWarmupEntryFilter,App.bGpuFarWarmupKernelFences,WarmupError)) {std::fprintf(stderr,"[GpuShaderWarmupError] queue: %s\n",WarmupError.c_str());return 5;} if(!VoxelForgeGpuFarViewer::CompleteFarShaderWarmup(App.Device,App.Context, App.GpuFarShaderPath,WarmupError)) {std::fprintf(stderr,"[GpuShaderWarmupError] completion: %s\n",WarmupError.c_str());return 5;} App.MarkGpuWarmupCacheReady(); uint64 WarmupDxgiUsage=0,WarmupDxgiBudget=0; if(VoxelForgeGpuFarViewer::QueryFarGpuMemory(App.Device,App.Context,App.GpuFarShaderPath, WarmupDxgiUsage,WarmupDxgiBudget,WarmupError)) std::printf("[GpuFarMemory] dxgi_local_sampled_peak_mb=%.3f budget_mb=%.3f\n", static_cast(WarmupDxgiUsage)/1048576.0, static_cast(WarmupDxgiBudget)/1048576.0); else std::printf("[GpuFarMemory] dxgi_local_sampled_peak_mb=unavailable reason=%s\n", WarmupError.c_str()); std::printf("[GpuShaderWarmupOnlyComplete] entry=%s total_ms=%.3f\n", App.GpuWarmupEntryFilter.empty()?"all":App.GpuWarmupEntryFilter.c_str(), std::chrono::duration(std::chrono::steady_clock::now()-WarmupOnlyStart).count()); return 0; } if(App.bGpuFarWarmupBeforeWorkers)App.StartGpuShaderWarmupAsync(); if(App.bGpuFarWarmupBeforeWorkers) { if(App.GpuShaderWarmupThread.joinable())App.GpuShaderWarmupThread.join(); if(!App.bGpuShaderWarmupQueueSucceeded) {std::fprintf(stderr,"[GpuShaderWarmupError] queue: %s\n",App.GpuShaderWarmupQueueError.c_str());return 5;} std::string WarmupError; if(!VoxelForgeGpuFarViewer::CompleteFarShaderWarmup(App.Device,App.Context, App.GpuFarShaderPath,WarmupError)) {std::fprintf(stderr,"[GpuShaderWarmupError] completion: %s\n",WarmupError.c_str());return 5;} App.MarkGpuWarmupCacheReady(); App.SetGpuWarmupContextProtection(false); App.bGpuWarmupCompleted=true; std::printf("[GpuShaderWarmupBeforeWorkers] completed_before_generation_workers=true\n"); } std::printf("[ColdTimeline] event=generation_setup_call at_ms=%.3f\n", std::chrono::duration( std::chrono::steady_clock::now()-ColdProcessStart).count()); App.StartGeneration(); MSG Message{}; const auto FramePeriod=std::chrono::duration(1.0/static_cast(FrameLimitHz)); auto NextFrameStart=std::chrono::steady_clock::now(); while(Message.message!=WM_QUIT) { if(PeekMessage(&Message,nullptr,0,0,PM_REMOVE)){TranslateMessage(&Message);DispatchMessage(&Message);} else { const auto Now=std::chrono::steady_clock::now(); if(Now(FramePeriod); const auto FrameEnd=std::chrono::steady_clock::now(); if(NextFrameStart