#pragma once #include "OwnerWorldLoader.h" #include "StreamingWorld.h" #include "LinuxScreenSpaceGate.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace StandaloneStreamBenchmark { struct FSceneExportWriter { std::ofstream File; bool bGood=true; std::uint32_t TileCount=0; template void Write(const T& Value) { File.write(reinterpret_cast(&Value),sizeof(Value)); bGood=bGood&&static_cast(File); } bool Open(const std::filesystem::path& Path,std::uint32_t VoxelSizeMicrons, const FVector& CameraVoxels,float YawDegrees,float PitchDegrees, std::uint32_t ExpectedTiles) { std::error_code Error; if(!Path.parent_path().empty()) std::filesystem::create_directories(Path.parent_path(),Error); if(Error)return false; File.open(Path,std::ios::binary|std::ios::trunc); if(!File)return false; constexpr char Magic[8]={'V','F','M','S','H','0','0','1'}; File.write(Magic,sizeof(Magic)); const std::uint32_t Version=1; Write(Version);Write(VoxelSizeMicrons);Write(ExpectedTiles); const double MicronsToMeters=static_cast(VoxelSizeMicrons)/1000000.0; const double Camera[3]={CameraVoxels.X*MicronsToMeters, CameraVoxels.Y*MicronsToMeters,CameraVoxels.Z*MicronsToMeters}; for(const double Value:Camera)Write(Value); const double Yaw=YawDegrees,Pitch=PitchDegrees; Write(Yaw);Write(Pitch); return bGood; } void Add(const FStandaloneCpuTile& Tile) { const std::int32_t Key[4]={Tile.Key.Coord.X,Tile.Key.Coord.Y, Tile.Key.Coord.Z,Tile.Key.Level}; for(const auto Value:Key)Write(Value); const std::uint32_t SurfaceVertexCount=Tile.SurfaceVertexCount; const std::uint32_t SkirtTriangleCount=Tile.SkirtTriangleCount; const std::uint32_t VertexCount=static_cast(Tile.Vertices.size()); const std::uint32_t IndexCount=static_cast(Tile.Indices.size()); const std::uint32_t MaskCount=static_cast(Tile.TriangleSkirtFaceMasks.size()); Write(SurfaceVertexCount);Write(SkirtTriangleCount); Write(VertexCount);Write(IndexCount);Write(MaskCount); for(const FStandaloneCpuVertex& Vertex:Tile.Vertices) for(const float Value:Vertex.Position)Write(Value); for(const FStandaloneCpuVertex& Vertex:Tile.Vertices) for(const float Value:Vertex.Normal)Write(Value); if(IndexCount) File.write(reinterpret_cast(Tile.Indices.data()), static_cast(sizeof(std::uint32_t)*Tile.Indices.size())); if(MaskCount) File.write(reinterpret_cast(Tile.TriangleSkirtFaceMasks.data()), static_cast(Tile.TriangleSkirtFaceMasks.size())); bGood=bGood&&static_cast(File); ++TileCount; } bool Close(std::uint32_t ExpectedTiles) { File.flush(); const bool bComplete=bGood&&static_cast(File)&&TileCount==ExpectedTiles; File.close(); return bComplete; } }; inline 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; }; inline 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; } inline 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,bool bProfileColumnOverlap, int32 FarHorizonLOD8InteriorStepVoxels,bool bReportMeshCoverage=false, const std::filesystem::path& MeshExportPath={},float CameraYawDegrees=0.0f, float CameraPitchDegrees=0.0f,bool bScreenSpaceGate=false, bool bUseSharedColumnCache=true,FVector CameraStepVoxels=FVector::ZeroVector) { using Clock=std::chrono::steady_clock; FStandaloneOwnerWorld& World=*OwnerWorld; const VoxelForgeCore::WorldAssemblyManifest* Assembly=CoreSnapshot.worldAssembly(); std::array ClosestDisplayDistances{}; std::array PixelBudgetsSubvoxels{}; if(bScreenSpaceGate) { ClosestDisplayDistances=StandaloneScreenSpaceGate::ClosestDisplayedDistancesMeters( World,CameraPositionVoxels,World.CoreVoxelSizeMicrons); const double VoxelMeters=static_cast(World.CoreVoxelSizeMicrons)/1000000.0; for(int32 Lod=3;Lod<=World.MaxClipLevel&&Lod<9;++Lod) PixelBudgetsSubvoxels[static_cast(Lod)]=static_cast(std::floor( ClosestDisplayDistances[static_cast(Lod)] *StandaloneScreenSpaceGate::OnePixelRadians/VoxelMeters *VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)); } 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()); const bool bHasCameraStep=std::abs(CameraStepVoxels.X)+std::abs(CameraStepVoxels.Y) +std::abs(CameraStepVoxels.Z)>1.0e-6f; FStandaloneDesiredTileSet MovedDesired; if(bHasCameraStep) { const FVector MovedCamera=CameraPositionVoxels+CameraStepVoxels; MovedDesired=StandaloneWorldMesher::BuildDesiredSet(World,MovedCamera); const auto MovedCoreTiles=Shape.desiredTiles({MovedCamera.X,MovedCamera.Y,MovedCamera.Z}); MovedDesired.Tiles.clear();MovedDesired.Tiles.reserve(MovedCoreTiles.size()); for(const auto& Key:MovedCoreTiles) MovedDesired.Tiles.emplace_back(FIntVector(Key.coordinate.x,Key.coordinate.y,Key.coordinate.z),Key.lod); if(MaxLevel>=0) MovedDesired.Tiles.erase(std::remove_if(MovedDesired.Tiles.begin(),MovedDesired.Tiles.end(), [&](const FVoxelTileKey& Tile){return Tile.Level>MaxLevel;}),MovedDesired.Tiles.end()); } if(!Desired.Tiles.empty()) { FIntVector volumeMin(INT32_MAX,INT32_MAX,INT32_MAX); FIntVector volumeMax(INT32_MIN,INT32_MIN,INT32_MIN); int32 minimumLod=INT32_MAX,maximumLod=INT32_MIN; for(const FVoxelTileKey& tile:Desired.Tiles) { const FIntVector origin=tile.OriginVoxels(); const int32 extent=tile.ExtentVoxels(); volumeMin.X=std::min(volumeMin.X,origin.X); volumeMin.Y=std::min(volumeMin.Y,origin.Y); volumeMin.Z=std::min(volumeMin.Z,origin.Z); volumeMax.X=std::max(volumeMax.X,origin.X+extent); volumeMax.Y=std::max(volumeMax.Y,origin.Y+extent); volumeMax.Z=std::max(volumeMax.Z,origin.Z+extent); minimumLod=std::min(minimumLod,tile.Level); maximumLod=std::max(maximumLod,tile.Level); } std::printf("[PipelineVolume] tiles=%zu lod=%d..%d min_voxel=(%d,%d,%d) max_voxel=(%d,%d,%d)\n", Desired.Tiles.size(),minimumLod,maximumLod,volumeMin.X,volumeMin.Y,volumeMin.Z, volumeMax.X,volumeMax.Y,volumeMax.Z); } 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); const auto AccumulateBounds=[&](const std::vector& Tiles) { for(const FVoxelTileKey& Tile: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,bProfileColumnOverlap, FarHorizonLOD8InteriorStepVoxels,bUseSharedColumnCache); if(bScreenSpaceGate)Streamer.SetMesherStageProfilingEnabled(true); 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; } FSceneExportWriter SceneExport; const bool bExportRequested=!MeshExportPath.empty(); bool bSceneExportPassing=true; if(bExportRequested) { bSceneExportPassing=SceneExport.Open(MeshExportPath,World.CoreVoxelSizeMicrons, CameraPositionVoxels,CameraYawDegrees,CameraPitchDegrees, static_cast(Update.DesiredTiles)); if(!bSceneExportPassing) { Streamer.Stop(); std::fprintf(stderr,"[MeshSceneExport] FAIL: could not open %s\n", MeshExportPath.string().c_str()); return 8; } } std::vector DensityRows,MeshRows,PayloadRows,TopologyRows; int32 Finished=0,NeighborhoodFinished=0,FullDetailFinished=0; int32 FullDetailExpected=0; uint64 WholeNonEmptyMeshTiles=0,WholeTriangleCount=0; struct FColumnXY { std::int64_t X=0,Y=0; bool operator==(const FColumnXY&)const=default; }; struct FColumnXYHash { std::size_t operator()(const FColumnXY& Value)const noexcept { const std::size_t X=std::hash{}(Value.X); const std::size_t Y=std::hash{}(Value.Y); return X^(Y+static_cast(0x9E3779B9u)+(X<<6)+(X>>2)); } }; struct FColumnEvaluationEvent { FColumnXY XY; FVoxelTileKey Tile; std::uint64_t WorkerHash=0; std::uint64_t Sequence=0; bool bOutsideTileFootprint=false; }; std::array,9> ColumnEventsByLOD; std::array ColumnEvaluationEventsByLOD{},UniqueColumnCoordinatesByLOD{}; std::array ColumnDuplicateEventsByLOD{},SameWorkerEvictedRepeatsByLOD{}; std::array DifferentWorkerRepeatsByLOD{},HaloNormalRepeatsByLOD{}; std::array HaloNormalEvaluationsByLOD{},NeighbourDuplicateEventsByLOD{}; std::array CrossWorkerNeighbourDuplicateEventsByLOD{}; std::array ColumnCaptureTilesByLOD{},ExpectedTilesByLOD{}; std::array ColumnCaptureCompleteByLOD{}; ColumnCaptureCompleteByLOD.fill(true); std::array WorkerSecondsByLOD{}; std::array ColumnEvalMsByLOD{},MarchingExclusiveMsByLOD{}; std::array GroundRefineExclusiveMsByLOD{},CapRefineExclusiveMsByLOD{}; std::array MeshAssemblyMsByLOD{}; std::array SkirtMsByLOD{}; std::array SkirtTrianglesByLOD{}; std::array TileCountByLOD{}; for(const FVoxelTileKey& Tile:Desired.Tiles) if(Tile.Level>=0&&Tile.Level(ExpectedTilesByLOD.size())) ++ExpectedTilesByLOD[static_cast(Tile.Level)]; const auto AreSameLODNeighbours=[](const FVoxelTileKey& A,const FVoxelTileKey& B) { if(A.Level!=B.Level)return false; const std::int64_t DX=std::abs(static_cast(A.Coord.X)-B.Coord.X); const std::int64_t DY=std::abs(static_cast(A.Coord.Y)-B.Coord.Y); const std::int64_t DZ=std::abs(static_cast(A.Coord.Z)-B.Coord.Z); return std::max({DX,DY,DZ})<=1&&(DX+DY+DZ)>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,9> GateSampleTiles{}; std::array GateSampleDistances{}; GateSampleDistances.fill(std::numeric_limits::infinity()); Clock::time_point NeighborhoodReady{},FullDetailReady{},WholeViewReady{}; bool bNeighborhoodReported=false,bFullDetailReported=false; while(Finished Ready=Streamer.TakeReady(); if(Ready.empty()){std::this_thread::sleep_for(std::chrono::milliseconds(1));continue;} for(const FStandaloneCpuTile& Tile:Ready) { if(bExportRequested)SceneExport.Add(Tile); ++Finished; if(bReportMeshCoverage) { const uint64 TileTriangleCount=static_cast(Tile.Indices.size()/3); WholeTriangleCount+=TileTriangleCount; if(TileTriangleCount>0)++WholeNonEmptyMeshTiles; } if(Tile.Key.Level>=0&&Tile.Key.Level(TileCountByLOD.size())) { const std::size_t LOD=static_cast(Tile.Key.Level); ++TileCountByLOD[LOD]; WorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds; ColumnEvalMsByLOD[LOD]+=Tile.CoreDiagnostics.columnEvaluationExclusiveMilliseconds; MarchingExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.marchingCubesExclusiveMilliseconds; GroundRefineExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.groundRefinementExclusiveMilliseconds; CapRefineExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.capRefinementExclusiveMilliseconds; MeshAssemblyMsByLOD[LOD]+=Tile.CoreDiagnostics.meshAssemblyMilliseconds; SkirtMsByLOD[LOD]+=Tile.CoreDiagnostics.marchingCubesSkirtMilliseconds; SkirtTrianglesByLOD[LOD]+=Tile.SkirtTriangleCount; if(bScreenSpaceGate&&Assembly&&Tile.Key.Level>=3&&Tile.Key.Level<9 &&!Tile.Vertices.empty() &&StandaloneScreenSpaceGate::TileHasNativeSurface(Tile.Key,*Assembly, static_cast(World.CoreVoxelSizeMicrons)/1000000.0)) { const double Distance=StandaloneScreenSpaceGate::TileAabbDistanceMeters( Tile.Key,CameraPositionVoxels, static_cast(World.CoreVoxelSizeMicrons)/1000000.0); const bool bCloser=DistanceKey); if(bCloser||(bTied&&bKeyLess)) {GateSampleDistances[LOD]=Distance;GateSampleTiles[LOD]=Tile;} } } if(bProfileColumnOverlap&&Tile.Key.Level>=0 &&Tile.Key.Level(ColumnCaptureTilesByLOD.size())) { const std::size_t LOD=static_cast(Tile.Key.Level); ++ColumnCaptureTilesByLOD[LOD]; ColumnCaptureCompleteByLOD[LOD]=ColumnCaptureCompleteByLOD[LOD] &&Tile.CoreDiagnostics.columnCoordinateCaptureComplete; auto& Events=ColumnEventsByLOD[LOD]; for(const auto& Coordinate:Tile.CoreDiagnostics.evaluatedColumnCoordinates) { Events.push_back({{Coordinate.x,Coordinate.y},Tile.Key, Tile.CoreDiagnostics.columnEvaluationWorkerHash,Coordinate.sequence, Coordinate.outsideTileFootprint}); } } 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; } } if(bHasCameraStep) { const auto MovingStart=Clock::now(); const auto MovingUpdate=Streamer.UpdateDesiredWithSet(MovedDesired,Desired.Tiles,1); std::array MovingTilesByLOD{}; std::array MovingWorkerSecondsByLOD{}; int32 MovingFinished=0; while(MovingFinished Ready=Streamer.TakeReady(); if(Ready.empty()) {std::this_thread::sleep_for(std::chrono::milliseconds(1));continue;} for(const FStandaloneCpuTile& Tile:Ready) { ++MovingFinished; if(Tile.Key.Level>=0&&Tile.Key.Level(MovingTilesByLOD.size())) { const std::size_t LOD=static_cast(Tile.Key.Level); ++MovingTilesByLOD[LOD]; MovingWorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds; } } } const double MovingWallSeconds=std::chrono::duration(Clock::now()-MovingStart).count(); const double StepDistanceMeters=std::sqrt( static_cast(CameraStepVoxels.X)*CameraStepVoxels.X +static_cast(CameraStepVoxels.Y)*CameraStepVoxels.Y +static_cast(CameraStepVoxels.Z)*CameraStepVoxels.Z) *static_cast(World.CoreVoxelSizeMicrons)/1000000.0; std::printf("[MovingCameraStep] step_voxels=(%.3f,%.3f,%.3f) distance_m=%.3f desired_tiles=%zu new_tiles=%d completed=%d wall_s=%.6f shared_column_cache=%s\n", CameraStepVoxels.X,CameraStepVoxels.Y,CameraStepVoxels.Z,StepDistanceMeters, MovedDesired.Tiles.size(),MovingUpdate.NewJobs,MovingFinished,MovingWallSeconds, bUseSharedColumnCache?"on":"off"); for(std::size_t LOD=0;LOD(MovingTilesByLOD[LOD]), MovingWorkerSecondsByLOD[LOD]); } Streamer.Stop(); bool bScreenSpaceGatePassing=true; if(bScreenSpaceGate) { if(Assembly) bScreenSpaceGatePassing=StandaloneScreenSpaceGate::Run(GateSampleTiles, Streamer,*Assembly,ClosestDisplayDistances,World.CoreVoxelSizeMicrons, World.MaxClipLevel,PixelBudgetsSubvoxels,CameraYawDegrees, CameraPitchDegrees); else {std::fprintf(stderr,"[ScreenSpaceGateResult] no-world-assembly status=REJECT\n");bScreenSpaceGatePassing=false;} } if(bExportRequested) { bSceneExportPassing=SceneExport.Close(static_cast(Update.DesiredTiles)); std::error_code FileSizeError; const std::uintmax_t ExportBytes=std::filesystem::file_size(MeshExportPath,FileSizeError); std::printf("[MeshSceneExport] tiles=%u expected=%d bytes=%llu status=%s path=%s\n", SceneExport.TileCount,Update.DesiredTiles, static_cast(FileSizeError?0:ExportBytes), bSceneExportPassing?"PASS":"FAIL",MeshExportPath.string().c_str()); bSceneExportPassing=bSceneExportPassing&&!FileSizeError; } if(bProfileColumnOverlap) { struct FColumnPriorUse { FVoxelTileKey Tile; std::uint64_t WorkerHash=0; }; for(std::size_t LOD=0;LOD,FColumnXYHash> UsesByXY; UsesByXY.reserve(Events.size()); for(const FColumnEvaluationEvent& Event:Events) { ++ColumnEvaluationEventsByLOD[LOD]; if(Event.bOutsideTileFootprint)++HaloNormalEvaluationsByLOD[LOD]; auto [Found,Inserted]=UsesByXY.try_emplace(Event.XY); auto& PriorUses=Found->second; if(Inserted) { ++UniqueColumnCoordinatesByLOD[LOD]; PriorUses.push_back({Event.Tile,Event.WorkerHash}); continue; } ++ColumnDuplicateEventsByLOD[LOD]; if(Event.bOutsideTileFootprint) ++HaloNormalRepeatsByLOD[LOD]; else { const bool bSameWorkerSeen=std::any_of(PriorUses.begin(),PriorUses.end(), [&](const FColumnPriorUse& Prior) {return Prior.WorkerHash==Event.WorkerHash;}); if(bSameWorkerSeen)++SameWorkerEvictedRepeatsByLOD[LOD]; else ++DifferentWorkerRepeatsByLOD[LOD]; } bool bHasNeighbourDuplicate=false,bHasCrossWorkerNeighbourDuplicate=false; for(const FColumnPriorUse& Prior:PriorUses) { if(!AreSameLODNeighbours(Prior.Tile,Event.Tile))continue; bHasNeighbourDuplicate=true; bHasCrossWorkerNeighbourDuplicate=bHasCrossWorkerNeighbourDuplicate ||Prior.WorkerHash!=Event.WorkerHash; } if(bHasNeighbourDuplicate)++NeighbourDuplicateEventsByLOD[LOD]; if(bHasCrossWorkerNeighbourDuplicate) ++CrossWorkerNeighbourDuplicateEventsByLOD[LOD]; PriorUses.push_back({Event.Tile,Event.WorkerHash}); } } } bool bColumnOverlapCapturePassing=true; if(bProfileColumnOverlap) { for(std::size_t LOD=0;LOD(ColumnCaptureTilesByLOD[LOD]), static_cast(ExpectedTilesByLOD[LOD]), static_cast(ColumnEvaluationEventsByLOD[LOD]), static_cast(UniqueColumnCoordinatesByLOD[LOD]), static_cast(ColumnDuplicateEventsByLOD[LOD]), static_cast(SameWorkerEvictedRepeatsByLOD[LOD]), static_cast(DifferentWorkerRepeatsByLOD[LOD]), static_cast(HaloNormalRepeatsByLOD[LOD]), static_cast(HaloNormalEvaluationsByLOD[LOD]), static_cast(NeighbourDuplicateEventsByLOD[LOD]), static_cast(CrossWorkerNeighbourDuplicateEventsByLOD[LOD]), bLODComplete?1:0); } } for(std::size_t LOD=0;LOD(TileCountByLOD[LOD]),WorkerSecondsByLOD[LOD], ColumnEvalMsByLOD[LOD],MarchingExclusiveMsByLOD[LOD], GroundRefineExclusiveMsByLOD[LOD],CapRefineExclusiveMsByLOD[LOD], SkirtMsByLOD[LOD],static_cast(SkirtTrianglesByLOD[LOD]), MeshAssemblyMsByLOD[LOD]); } 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); if(bReportMeshCoverage) std::printf("[PipelineMeshCoverage] tiles=%d nonempty_mesh_tiles=%llu indexed_triangles=%llu\n", Finished,static_cast(WholeNonEmptyMeshTiles), static_cast(WholeTriangleCount)); 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))); for(std::size_t LOD=0;LOD& Rows) { std::vector Selected; for(const FHashedTile& Row:Rows) if(Row.Key.Level==static_cast(LOD))Selected.push_back(Row); return Selected; }; auto LodDensity=FilterLOD(DensityRows),LodMesh=FilterLOD(MeshRows); auto LodPayload=FilterLOD(PayloadRows),LodTopology=FilterLOD(TopologyRows); std::printf("[PipelineLODHash] lod=%zu tiles=%llu density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx\n", LOD,static_cast(TileCountByLOD[LOD]), static_cast(HashTileRows(LodDensity)), static_cast(HashTileRows(LodMesh)), static_cast(HashTileRows(LodPayload)), static_cast(HashTileRows(LodTopology))); } const std::array QueryPoints={{ {CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z}, {CameraPositionVoxels.X+8.0,CameraPositionVoxels.Y,CameraPositionVoxels.Z}, {CameraPositionVoxels.X-8.0,CameraPositionVoxels.Y,CameraPositionVoxels.Z}, {CameraPositionVoxels.X,CameraPositionVoxels.Y+8.0,CameraPositionVoxels.Z}, {CameraPositionVoxels.X,CameraPositionVoxels.Y-8.0,CameraPositionVoxels.Z}, {CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z+8.0}, {CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z-8.0}, {CameraPositionVoxels.X+64.0,CameraPositionVoxels.Y-32.0,CameraPositionVoxels.Z+16.0}, {CameraPositionVoxels.X-128.0,CameraPositionVoxels.Y+96.0,CameraPositionVoxels.Z-64.0}}}; uint64 ExactDensityHash=14695981039346656037ull; uint64 ExactUnclampedHash=14695981039346656037ull; uint64 ExactDetailHash=14695981039346656037ull; uint64 ExactCollisionHash=14695981039346656037ull; for(const auto& Point:QueryPoints) { const float Density=Shape.densityAt(Point); const float Unclamped=Shape.unclampedDensityAt(Point); const auto Detail=Shape.detailSampleAt(Point); HashWord(ExactDensityHash,std::bit_cast(Density),4); HashWord(ExactUnclampedHash,std::bit_cast(Unclamped),4); HashWord(ExactDetailHash,std::bit_cast(Detail.displacement),4); HashWord(ExactDetailHash,std::bit_cast(Detail.caveInfluence),4); HashWord(ExactDetailHash,std::bit_cast(Detail.floorInfluence),4); HashWord(ExactCollisionHash,Shape.isSolidAt(Point)?1u:0u,1); } std::printf("[PipelineExactQueryHash] probes=%zu density=0x%016llx unclamped=0x%016llx detail=0x%016llx collision=0x%016llx path=direct-Core-queries\n", QueryPoints.size(),static_cast(ExactDensityHash), static_cast(ExactUnclampedHash), static_cast(ExactDetailHash), static_cast(ExactCollisionHash)); } return NeighborhoodFinished==static_cast(Neighborhood.size()) &&FullDetailFinished==FullDetailExpected&&Finished==Update.DesiredTiles&&bHashesPassing &&(!bProfileColumnOverlap||bColumnOverlapCapturePassing) &&(!bExportRequested||bSceneExportPassing)&&bScreenSpaceGatePassing?0:6; } } // namespace StandaloneStreamBenchmark