standalone: VoxelForgeCore link-safe next to Unreal -- internals in vfcore::detail, symbol check
- The copied generator, mesher and Compat stand-ins compile inside vfcore::detail. - CheckCoreSymbols.ps1 (run by Build.ps1) fails on any unqualified Unreal-style symbol in the library: 16,255 on557f6aa, 0 now. A UE 5.7 CoreMinimal.h + VoxelForgeCore.h smoke compile passes. - Output identical: 11 hash rows at W1/W8, routes 5642/5642, look/passage/far audits pass, bad-shell control fails, six captures byte-identical. Cost, measured by me interleaved (8 workers, cold, 4 runs each, first run excluded): 0.963 s vs 0.937 s for557f6aa, ~27 ms in shape compilation; same math, so codegen/inlining. To be found. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
557f6aac30
commit
aeeedaa73d
11 files changed
+461
-87
No files matched your search
@@ -26,6 +26,7 @@
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <numeric>
|
||||
@@ -351,6 +352,7 @@ namespace
|
||||
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;
|
||||
@@ -656,7 +658,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
ShapeWorld.reset();
|
||||
Snapshot={};
|
||||
World=std::make_shared<FStandaloneOwnerWorld>();
|
||||
if(!StandaloneOwnerLoader::Load(DataPath,*World,Error))return false;
|
||||
if(!StandaloneOwnerLoader::Resolve(OwnerJsonRoot,*World,Error))return false;
|
||||
if(!bParityChecked&&Seed==World->Seed&&!bRoundTunnels)PrintParity();
|
||||
const int32 ExportClipRadius=World->ClipRadius;
|
||||
World->ClipRadius=ClipRadius;
|
||||
@@ -722,8 +724,10 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
Min.X-=NearBuildPad;Min.Y-=NearBuildPad;Min.Z-=NearBuildPad;
|
||||
Max.X+=NearBuildPad;Max.Y+=NearBuildPad;Max.Z+=NearBuildPad;
|
||||
}
|
||||
Snapshot=VoxelForgeCore::MakeStandaloneSnapshot(World);
|
||||
if(!Snapshot){Error="the standalone adapter could not make a resolved core snapshot";return false;}
|
||||
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<VoxelForgeCore::World>(Snapshot);
|
||||
const int32 ShapeWorkers=bNeighborhoodOnly?(WorkerCount>=8?2:1):WorkerCount;
|
||||
VoxelForgeCore::ShapeBuildRequest Request;
|
||||
@@ -1941,6 +1945,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
}
|
||||
|
||||
int RunPipelinedStreamingBenchmark(std::shared_ptr<FStandaloneOwnerWorld> 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,
|
||||
@@ -1948,7 +1953,15 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
{
|
||||
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());
|
||||
@@ -1978,7 +1991,15 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
if(Neighborhood.size()!=27)
|
||||
{std::fprintf(stderr,"[StreamPipeline] expected 27 player-neighborhood tiles, found %zu.\n",Neighborhood.size());return 7;}
|
||||
|
||||
VoxelForgeCore::World Shape(VoxelForgeCore::MakeStandaloneSnapshot(OwnerWorld));
|
||||
// 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();
|
||||
@@ -1989,8 +2010,8 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
ShapeRequest.clipMaxVoxel={ClipMax.X,ClipMax.Y,ClipMax.Z};
|
||||
ShapeRequest.workerLimit=static_cast<uint32>(std::clamp(WorkerCount,1,8));
|
||||
ShapeRequest.detail=DetailVariant;ShapeRequest.includeFarWorld=bIncludeFarWorld;
|
||||
ShapeRequest.roundTunnels=World.Generator->bStandaloneResearchRoundTunnels;
|
||||
ShapeRequest.enhancedTunnelWalls=World.Generator->bStandaloneResearchEnhancedWalls;
|
||||
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();
|
||||
@@ -1998,7 +2019,7 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
FStandaloneStreamingGenerator Streamer(World,WorkerCount,bHashDensity,nullptr,MaxLevel,
|
||||
bSkipUvAndColors,bSkipMaterialGroups,bSkipUV,bSkipColors,&Shape);
|
||||
const auto StreamStart=Clock::now();
|
||||
const FStandaloneStreamingUpdate Update=Streamer.Start(CameraPositionVoxels);
|
||||
const FStandaloneStreamingUpdate Update=Streamer.StartWithDesired(Desired);
|
||||
if(Update.DesiredTiles!=static_cast<int32>(Desired.Tiles.size()))
|
||||
{
|
||||
Streamer.Stop();
|
||||
@@ -2153,11 +2174,23 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
|
||||
auto PlayerNeighborhoodCompleted=std::chrono::steady_clock::time_point{};
|
||||
std::vector<FStandaloneCpuTile> CacheTiles;
|
||||
if(!BakeCachePath.empty())CacheTiles.reserve(Desired.Tiles.size());
|
||||
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=Streamer.Start(CameraPositionVoxels);
|
||||
const FStandaloneStreamingUpdate Update=CoreWorld
|
||||
?Streamer.StartWithDesired(Desired):Streamer.Start(CameraPositionVoxels);
|
||||
const double LOD0Width=static_cast<double>(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",
|
||||
@@ -2564,7 +2597,17 @@ int main(int Argc,char** Argv)
|
||||
App.bProfileDetailBand=bProfileDetailBand;
|
||||
std::string Error;
|
||||
App.World=std::make_shared<FStandaloneOwnerWorld>();
|
||||
if(!StandaloneOwnerLoader::Load(App.DataPath,*App.World,Error)){std::fprintf(stderr,"Owner data load failed: %s\n",Error.c_str());return 2;}
|
||||
{
|
||||
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<char>(JsonFile),std::istreambuf_iterator<char>{}};
|
||||
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;}
|
||||
App.Seed=App.World->Seed;
|
||||
if(App.bParityOnly)
|
||||
{
|
||||
@@ -2597,6 +2640,14 @@ int main(int Argc,char** Argv)
|
||||
&&!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.bShapeAuditOnly)
|
||||
{
|
||||
if(bPassageDetailAuditOnly)
|
||||
@@ -2614,7 +2665,7 @@ int main(int Argc,char** Argv)
|
||||
if(bStreamBenchmark)
|
||||
{
|
||||
if(bStreamPipeline)
|
||||
return RunPipelinedStreamingBenchmark(App.World,
|
||||
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,
|
||||
|
||||
Reference in new issue
Block a user