Crash: crossing tiles were coalesced into one huge rectangle, and BuildSpatialBins tried to resize to ~4.3e17 bytes (std::bad_alloc; the L7 32 m failure had the same cause). Analytic regions now skip unread dense bins and compile in world-aligned 128-voxel pages, published together; out-of-range keys error before allocation. 24 m, 32 m and 1 km crossings pass (1 km: 72 pages, peak RSS 700 MiB). Spawn: World::isTileShapeFree proves LOD0 SurfaceWorld tiles that never read the cave shape; those start before shape compile, and all others wait. Reviewer W12 no-hash: near ring 0.337 -> 0.159 s, whole view +2.1%. All SurfaceWorld/FloatingIslands hashes unchanged (W1/W8/W12, both compilers, forced-overlap run). Unreal VoxelWorld.cpp adapter changed but NOT built here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
375 lines
21 KiB
C++
375 lines
21 KiB
C++
#include "OwnerWorldLoader.h"
|
|
#include "StandaloneCoreScheduler.h"
|
|
#include "StreamBenchmarkPipeline.h"
|
|
#include "WorldAssemblyPrototype.h"
|
|
#include "StandaloneTlsProbe.h"
|
|
#include "../Core/src/StandaloneSnapshotAdapter.h"
|
|
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
#include <cmath>
|
|
#include <cstdint>
|
|
#include <ctime>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <iterator>
|
|
#include <limits>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <string_view>
|
|
|
|
namespace
|
|
{
|
|
struct FOptions
|
|
{
|
|
std::filesystem::path DataPath;
|
|
int WorkerCount=8;
|
|
int ClipRadius=3;
|
|
int MaxClipLevel=8;
|
|
int MaxLevel=-1;
|
|
int FarHorizonLOD8InteriorStepVoxels=0;
|
|
bool WorldAssemblerPrototype=false;
|
|
bool StreamBenchmark=false;
|
|
bool StreamPipeline=false;
|
|
bool StreamHash=false;
|
|
bool ProfileColumnOverlap=false;
|
|
bool UseSharedColumnCache=true;
|
|
bool ForceGenerate=false;
|
|
bool MeshCoverage=false;
|
|
bool ScreenSpaceGate=false;
|
|
bool AuditUniformBlockProofs=false;
|
|
bool ProfileLodWork=false;
|
|
bool RegionCrossing=false;
|
|
bool AuditTileShapeReadiness=false;
|
|
int DiagnosticSlowShapeCompileMs=0;
|
|
bool HasSeedOverride=false;
|
|
int SeedOverride=0;
|
|
bool HasRenderDistanceOverride=false;
|
|
int RenderDistanceOverride=0;
|
|
bool FloatingIslandsRecipe=false;
|
|
bool TlsProbeRequested=false;
|
|
int TlsProbeWorkers=0;
|
|
std::string TlsProbeTouch="none";
|
|
bool HasCamera=false;
|
|
bool HasCameraStep=false;
|
|
bool AutoSurfaceCamera=false;
|
|
FVector CameraMeters=FVector::ZeroVector;
|
|
FVector CameraStepMeters=FVector::ZeroVector;
|
|
float CameraYawDegrees=0.0f;
|
|
float CameraPitchDegrees=0.0f;
|
|
std::filesystem::path MeshExportPath;
|
|
};
|
|
|
|
bool ParseInteger(std::string_view text,int& output)
|
|
{
|
|
if(text.empty())return false;
|
|
char* end=nullptr;
|
|
const std::string value(text);
|
|
const long parsed=std::strtol(value.c_str(),&end,10);
|
|
if(end==value.c_str()||*end!='\0'||parsed<INT32_MIN||parsed>INT32_MAX)return false;
|
|
output=static_cast<int>(parsed);
|
|
return true;
|
|
}
|
|
|
|
bool ParseCamera(std::string_view text,FVector& meters,float& yawDegrees,float& pitchDegrees)
|
|
{
|
|
const std::string values(text);
|
|
float x=0.0f,y=0.0f,z=0.0f,yaw=0.0f,pitch=0.0f;
|
|
if(std::sscanf(values.c_str(),"%f,%f,%f,%f,%f",&x,&y,&z,&yaw,&pitch)!=5)
|
|
return false;
|
|
meters={x,y,z};
|
|
yawDegrees=yaw;
|
|
pitchDegrees=pitch;
|
|
return true;
|
|
}
|
|
|
|
bool ParseCameraStep(std::string_view text,FVector& meters)
|
|
{
|
|
const std::string values(text);
|
|
float x=0.0f,y=0.0f,z=0.0f;
|
|
if(std::sscanf(values.c_str(),"%f,%f,%f",&x,&y,&z)!=3)return false;
|
|
meters={x,y,z};
|
|
return true;
|
|
}
|
|
|
|
bool ParseOptions(int argc,char** argv,FOptions& options)
|
|
{
|
|
const std::filesystem::path executable=std::filesystem::absolute(argv[0]);
|
|
options.DataPath=executable.parent_path().parent_path()/"data/owner_world.json";
|
|
for(int index=1;index<argc;++index)
|
|
{
|
|
const std::string_view arg(argv[index]);
|
|
const auto readInt=[&](std::string_view prefix,int& value)
|
|
{return arg.starts_with(prefix)&&ParseInteger(arg.substr(prefix.size()),value);};
|
|
if(arg=="--help"||arg=="-h")
|
|
{
|
|
std::printf("Usage: %s [owner_world.json] --world-assembler-prototype --stream-benchmark --stream-pipeline [options]\n"
|
|
" --workers=N --clip-radius=N --max-clip-level=N --max-level=N\n"
|
|
" --camera=X,Y,Z,YAW,PITCH (position in metres) --stream-hash\n"
|
|
" --camera-step=X,Y,Z (optional second view step in metres)\n"
|
|
" --region-crossing (compile entering Core regions at the camera step)\n"
|
|
" --column-cache=shared|thread-local (default: shared)\n"
|
|
" --mesh-export=FILE (write the exact generated tile meshes for offline rendering)\n"
|
|
" --profile-column-overlap --far-horizon-lod8-step=N --force-generate\n"
|
|
" --seed=N --recipe=surface-world|floating-islands\n"
|
|
" --auto-surface-camera (place the 27-tile cube on this seed's surface)\n"
|
|
" --mesh-coverage (report non-empty tiles and indexed triangles)\n"
|
|
" --screen-space-gate (measure display error and historical negative controls)\n"
|
|
" --audit-uniform-block-proofs (fill and check every interval-certified block)\n"
|
|
" --profile-lod-work (report per-LOD density sample counts)\n"
|
|
" --audit-tile-shape-readiness (run a deliberately mis-marked tile against the native-only guard)\n"
|
|
" --diagnostic-slow-shape-compile-ms=N (diagnostic overlap control; default 0)\n"
|
|
" --render-distance-chunks=N (0 disables the extra far ring)\n"
|
|
" --tls-probe=N (Linux worker TLS/stack measurement; N=0..12)\n"
|
|
" --tls-probe-touch=none|surface-world|floating-islands (first-use probe)\n"
|
|
" --process-affinity=MASK --process-priority=Normal --frame-limit=FPS (viewer compatibility only)\n",
|
|
argv[0]);
|
|
return false;
|
|
}
|
|
if(arg=="--world-assembler-prototype")options.WorldAssemblerPrototype=true;
|
|
else if(arg=="--stream-benchmark")options.StreamBenchmark=true;
|
|
else if(arg=="--stream-pipeline")options.StreamPipeline=true;
|
|
else if(arg=="--stream-hash")options.StreamHash=true;
|
|
else if(arg=="--profile-column-overlap")options.ProfileColumnOverlap=true;
|
|
else if(arg=="--force-generate")options.ForceGenerate=true;
|
|
else if(arg=="--mesh-coverage")options.MeshCoverage=true;
|
|
else if(arg=="--screen-space-gate")options.ScreenSpaceGate=true;
|
|
else if(arg=="--audit-uniform-block-proofs")options.AuditUniformBlockProofs=true;
|
|
else if(arg=="--profile-lod-work")options.ProfileLodWork=true;
|
|
else if(arg=="--region-crossing")options.RegionCrossing=true;
|
|
else if(arg=="--audit-tile-shape-readiness")options.AuditTileShapeReadiness=true;
|
|
else if(arg=="--auto-surface-camera")options.AutoSurfaceCamera=true;
|
|
else if(arg.starts_with("--recipe="))
|
|
{
|
|
const std::string_view recipe=arg.substr(std::string_view("--recipe=").size());
|
|
if(recipe=="surface-world")options.FloatingIslandsRecipe=false;
|
|
else if(recipe=="floating-islands")options.FloatingIslandsRecipe=true;
|
|
else {std::fprintf(stderr,"Invalid --recipe value: %.*s\n",static_cast<int>(recipe.size()),recipe.data());return false;}
|
|
}
|
|
else if(arg.starts_with("--seed="))
|
|
{if(!readInt("--seed=",options.SeedOverride))return false;options.HasSeedOverride=true;}
|
|
else if(arg.starts_with("--render-distance-chunks="))
|
|
{
|
|
if(!readInt("--render-distance-chunks=",options.RenderDistanceOverride))return false;
|
|
options.RenderDistanceOverride=std::max(0,options.RenderDistanceOverride);
|
|
options.HasRenderDistanceOverride=true;
|
|
}
|
|
else if(arg.starts_with("--tls-probe="))
|
|
{
|
|
if(!readInt("--tls-probe=",options.TlsProbeWorkers))return false;
|
|
if(options.TlsProbeWorkers<0||options.TlsProbeWorkers>12)
|
|
{std::fprintf(stderr,"--tls-probe must be in 0..12\n");return false;}
|
|
options.TlsProbeRequested=true;
|
|
}
|
|
else if(arg.starts_with("--tls-probe-touch="))
|
|
{
|
|
const std::string_view touch=arg.substr(std::string_view("--tls-probe-touch=").size());
|
|
if(touch!="none"&&touch!="surface-world"&&touch!="floating-islands")
|
|
{std::fprintf(stderr,"Invalid --tls-probe-touch value: %.*s\n",static_cast<int>(touch.size()),touch.data());return false;}
|
|
options.TlsProbeTouch=touch;
|
|
}
|
|
else if(arg.starts_with("--camera="))
|
|
{
|
|
if(!ParseCamera(arg.substr(9),options.CameraMeters,
|
|
options.CameraYawDegrees,options.CameraPitchDegrees))
|
|
{std::fprintf(stderr,"Invalid --camera value: %.*s\n",static_cast<int>(arg.size()),arg.data());return false;}
|
|
options.HasCamera=true;
|
|
}
|
|
else if(arg.starts_with("--camera-step="))
|
|
{
|
|
if(!ParseCameraStep(arg.substr(std::string_view("--camera-step=").size()),
|
|
options.CameraStepMeters))
|
|
{std::fprintf(stderr,"Invalid --camera-step value: %.*s\n",static_cast<int>(arg.size()),arg.data());return false;}
|
|
options.HasCameraStep=true;
|
|
}
|
|
else if(arg.starts_with("--column-cache="))
|
|
{
|
|
const std::string_view mode=arg.substr(std::string_view("--column-cache=").size());
|
|
if(mode=="shared")options.UseSharedColumnCache=true;
|
|
else if(mode=="thread-local")options.UseSharedColumnCache=false;
|
|
else {std::fprintf(stderr,"Invalid --column-cache value: %.*s\n",static_cast<int>(arg.size()),arg.data());return false;}
|
|
}
|
|
else if(arg.starts_with("--mesh-export="))
|
|
{
|
|
options.MeshExportPath=std::filesystem::path(arg.substr(14));
|
|
if(options.MeshExportPath.empty())
|
|
{std::fprintf(stderr,"--mesh-export needs a file path\n");return false;}
|
|
}
|
|
else if(arg.starts_with("--workers="))
|
|
{if(!readInt("--workers=",options.WorkerCount))return false;}
|
|
else if(arg.starts_with("--clip-radius="))
|
|
{if(!readInt("--clip-radius=",options.ClipRadius))return false;}
|
|
else if(arg.starts_with("--max-clip-level="))
|
|
{if(!readInt("--max-clip-level=",options.MaxClipLevel))return false;}
|
|
else if(arg.starts_with("--max-level="))
|
|
{if(!readInt("--max-level=",options.MaxLevel))return false;}
|
|
else if(arg.starts_with("--far-horizon-lod8-step="))
|
|
{if(!readInt("--far-horizon-lod8-step=",options.FarHorizonLOD8InteriorStepVoxels))return false;}
|
|
else if(arg.starts_with("--diagnostic-slow-shape-compile-ms="))
|
|
{if(!readInt("--diagnostic-slow-shape-compile-ms=",options.DiagnosticSlowShapeCompileMs))return false;}
|
|
else if(arg.starts_with("--process-affinity=")||arg.starts_with("--process-priority=")
|
|
||arg.starts_with("--frame-limit="))
|
|
{
|
|
// These viewer switches are accepted for command-line parity. The caller pins
|
|
// this headless process with taskset, and a headless run has no frame limiter.
|
|
}
|
|
else if(!arg.empty()&&arg.front()!='-')options.DataPath=std::filesystem::path(arg);
|
|
else
|
|
{std::fprintf(stderr,"Unknown option: %.*s\n",static_cast<int>(arg.size()),arg.data());return false;}
|
|
}
|
|
options.WorkerCount=std::clamp(options.WorkerCount,1,16);
|
|
options.ClipRadius=std::clamp(options.ClipRadius,1,64);
|
|
options.MaxClipLevel=std::clamp(options.MaxClipLevel,0,8);
|
|
options.FarHorizonLOD8InteriorStepVoxels=std::max(0,options.FarHorizonLOD8InteriorStepVoxels);
|
|
options.DiagnosticSlowShapeCompileMs=std::clamp(options.DiagnosticSlowShapeCompileMs,0,30000);
|
|
if(!options.TlsProbeRequested&&options.TlsProbeTouch!="none")
|
|
{std::fprintf(stderr,"--tls-probe-touch requires --tls-probe=N\n");return false;}
|
|
if(options.RegionCrossing&&!options.HasCameraStep)
|
|
{std::fprintf(stderr,"--region-crossing requires --camera-step=X,Y,Z\n");return false;}
|
|
if(options.TlsProbeRequested)return true;
|
|
if(!options.WorldAssemblerPrototype||!options.StreamBenchmark||!options.StreamPipeline)
|
|
{
|
|
std::fprintf(stderr,"This headless target runs the world-assembler streaming pipeline; pass --world-assembler-prototype --stream-benchmark --stream-pipeline.\n");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
int main(int argc,char** argv)
|
|
{
|
|
using Clock=std::chrono::steady_clock;
|
|
const auto coldStart=Clock::now();
|
|
FOptions options;
|
|
if(!ParseOptions(argc,argv,options))return 2;
|
|
if(options.TlsProbeRequested)
|
|
return StandaloneTlsProbe::Run(options.TlsProbeWorkers,options.TlsProbeTouch);
|
|
std::printf("[HeadlessConfig] data=%s workers=%d clip_radius=%d max_clip_level=%d max_level=%d hash=%s column_overlap=%s force_generate=%s recipe=%s shared_column_cache=%s camera_step_m=(%.3f,%.3f,%.3f) seed_override=%s render_distance_override=%s\n",
|
|
options.DataPath.string().c_str(),options.WorkerCount,options.ClipRadius,options.MaxClipLevel,
|
|
options.MaxLevel,options.StreamHash?"on":"off",options.ProfileColumnOverlap?"on":"off",
|
|
options.ForceGenerate?"on":"off",options.FloatingIslandsRecipe?"floating-islands":"surface-world",
|
|
options.UseSharedColumnCache?"on":"off",options.CameraStepMeters.X,options.CameraStepMeters.Y,
|
|
options.CameraStepMeters.Z,
|
|
options.HasSeedOverride?"yes":"no",options.HasRenderDistanceOverride?"yes":"no");
|
|
std::printf("[ColdTimeline] stage=owner_data_load begin_ms=%.3f\n",
|
|
std::chrono::duration<double,std::milli>(Clock::now()-coldStart).count());
|
|
|
|
std::string error;
|
|
auto ownerWorld=std::make_shared<FStandaloneOwnerWorld>();
|
|
VFJson::Value ownerJsonRoot;
|
|
{
|
|
std::ifstream jsonFile(options.DataPath,std::ios::binary);
|
|
if(!jsonFile)
|
|
{std::fprintf(stderr,"Owner data load failed: cannot open %s\n",options.DataPath.string().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",options.DataPath.string().c_str());return 2;}
|
|
if(!VFJson::Parser(std::move(ownerJsonText)).Parse(ownerJsonRoot,error))
|
|
{std::fprintf(stderr,"Owner data load failed: %s\n",error.c_str());return 2;}
|
|
}
|
|
if(options.HasSeedOverride
|
|
&&!StandaloneWorldAssemblyPrototype::OverrideStandaloneSeed(ownerJsonRoot,options.SeedOverride,error))
|
|
{std::fprintf(stderr,"Seed override failed: %s\n",error.c_str());return 2;}
|
|
if(options.HasRenderDistanceOverride
|
|
&&!StandaloneWorldAssemblyPrototype::OverrideStandaloneRenderDistance(
|
|
ownerJsonRoot,options.RenderDistanceOverride,error))
|
|
{std::fprintf(stderr,"Render-distance override failed: %s\n",error.c_str());return 2;}
|
|
if(options.FloatingIslandsRecipe
|
|
&&!StandaloneWorldAssemblyPrototype::SelectTopStrateAsFloatingIslands(ownerJsonRoot,error))
|
|
{std::fprintf(stderr,"Floating-island recipe selection failed: %s\n",error.c_str());return 2;}
|
|
if(!StandaloneOwnerLoader::Resolve(ownerJsonRoot,*ownerWorld,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<double,std::milli>(Clock::now()-coldStart).count());
|
|
|
|
const int seed=ownerWorld->Seed;
|
|
const int exportedMaxClipLevel=ownerWorld->MaxClipLevel;
|
|
ownerWorld->ClipRadius=options.ClipRadius;
|
|
ownerWorld->Settings->ClipRadius=options.ClipRadius;
|
|
ownerWorld->MaxClipLevel=options.MaxClipLevel;
|
|
ownerWorld->Settings->MaxClipLevel=options.MaxClipLevel;
|
|
if(exportedMaxClipLevel!=options.MaxClipLevel)
|
|
std::printf("Standalone max clip level override: exported=%d -> max_level=%d.\n",
|
|
exportedMaxClipLevel,options.MaxClipLevel);
|
|
|
|
FVector cameraVoxels=ownerWorld->ViewerStartVoxels;
|
|
if(options.HasCamera)
|
|
cameraVoxels=FVector(options.CameraMeters.X*4.0f,options.CameraMeters.Y*4.0f,options.CameraMeters.Z*4.0f);
|
|
|
|
const auto planStart=Clock::now();
|
|
VoxelForgeCore::WorldAssemblyManifest worldAssembly;
|
|
if(!StandaloneWorldAssemblyPrototype::AttachRound1WorldAssemblyPrototype(
|
|
*ownerWorld,ownerJsonRoot,error,{},&worldAssembly))
|
|
{std::fprintf(stderr,"World assembler prototype setup failed: %s\n",error.c_str());return 2;}
|
|
if(options.FloatingIslandsRecipe
|
|
&&!StandaloneWorldAssemblyPrototype::AttachFloatingIslandWorldAssembly(
|
|
*ownerWorld,ownerJsonRoot,worldAssembly,error))
|
|
{std::fprintf(stderr,"Floating-island assembly setup failed: %s\n",error.c_str());return 2;}
|
|
if(options.AutoSurfaceCamera)
|
|
{
|
|
constexpr std::int64_t UnitsPerVoxel=VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
|
|
if(options.FloatingIslandsRecipe)
|
|
{
|
|
const VoxelForgeCore::FloatingIslandAnchorV1* chosen=nullptr;
|
|
for(const auto& islandSet:worldAssembly.floatingIslands)
|
|
for(const auto& island:islandSet.manifest.plan.islands)
|
|
if(!chosen||island.radiusSubvoxels>chosen->radiusSubvoxels)chosen=&island;
|
|
if(!chosen)
|
|
{std::fprintf(stderr,"[SeedSurfacePlacement] FAIL: island plan has no anchors\n");return 2;}
|
|
cameraVoxels={
|
|
static_cast<float>(chosen->centerSubvoxels[0])/UnitsPerVoxel,
|
|
static_cast<float>(chosen->centerSubvoxels[1])/UnitsPerVoxel,
|
|
static_cast<float>(chosen->centerSubvoxels[2])/UnitsPerVoxel};
|
|
std::printf("[SeedSurfacePlacement] recipe=floating-islands seed=%d island_radius_vox=%.3f camera_voxel=(%.6f,%.6f,%.6f) status=PASS\n",
|
|
seed,static_cast<double>(chosen->radiusSubvoxels)/UnitsPerVoxel,
|
|
cameraVoxels.X,cameraVoxels.Y,cameraVoxels.Z);
|
|
}
|
|
else
|
|
{
|
|
const auto xSubvoxels=static_cast<std::int64_t>(std::llround(cameraVoxels.X*UnitsPerVoxel));
|
|
const auto ySubvoxels=static_cast<std::int64_t>(std::llround(cameraVoxels.Y*UnitsPerVoxel));
|
|
const auto currentZSubvoxels=static_cast<std::int64_t>(std::llround(cameraVoxels.Z*UnitsPerVoxel));
|
|
std::int64_t selectedGround=0,bestDistance=std::numeric_limits<std::int64_t>::max();
|
|
for(const auto& stratum:worldAssembly.plan.strates)
|
|
{
|
|
VoxelForgeCore::Heightfield2D field(worldAssembly.recipe,stratum);
|
|
if(!field.isValid())continue;
|
|
const auto column=field.point(xSubvoxels,ySubvoxels,0);
|
|
const std::int64_t distance=std::abs(column.groundHeightSubvoxels-currentZSubvoxels);
|
|
if(distance<bestDistance)
|
|
{bestDistance=distance;selectedGround=column.groundHeightSubvoxels;}
|
|
}
|
|
if(bestDistance==std::numeric_limits<std::int64_t>::max())
|
|
{std::fprintf(stderr,"[SeedSurfacePlacement] FAIL: no valid SurfaceWorld heightfield\n");return 2;}
|
|
cameraVoxels.Z=static_cast<float>(static_cast<double>(selectedGround)/UnitsPerVoxel);
|
|
std::printf("[SeedSurfacePlacement] recipe=surface-world seed=%d ground_voxel=%.6f camera_voxel=(%.6f,%.6f,%.6f) status=PASS\n",
|
|
seed,static_cast<double>(selectedGround)/UnitsPerVoxel,
|
|
cameraVoxels.X,cameraVoxels.Y,cameraVoxels.Z);
|
|
}
|
|
}
|
|
std::printf("[WorldAssemblerPlanTiming] total_ms=%.3f status=PASS\n",
|
|
std::chrono::duration<double,std::milli>(Clock::now()-planStart).count());
|
|
|
|
auto snapshot=VoxelForgeCore::MakeStandaloneSnapshotFromParsedJson(ownerJsonRoot,seed,
|
|
options.ClipRadius,options.MaxClipLevel,false,false,error);
|
|
if(!snapshot)
|
|
{std::fprintf(stderr,"Shape interval build failed: %s\n",error.c_str());return 2;}
|
|
|
|
FStandaloneCoreScheduler scheduler;
|
|
const FVector cameraStepVoxels=options.HasCameraStep
|
|
?FVector(options.CameraStepMeters.X*4.0f,options.CameraStepMeters.Y*4.0f,
|
|
options.CameraStepMeters.Z*4.0f):FVector::ZeroVector;
|
|
return StandaloneStreamBenchmark::RunPipelinedStreamingBenchmark(ownerWorld,snapshot,
|
|
cameraVoxels,options.WorkerCount,options.MaxLevel,VoxelForgeCore::DetailVariant::coherent,
|
|
scheduler,options.StreamHash,false,false,false,false,coldStart,
|
|
options.ProfileColumnOverlap,options.FarHorizonLOD8InteriorStepVoxels,
|
|
options.MeshCoverage,options.MeshExportPath,options.CameraYawDegrees,
|
|
options.CameraPitchDegrees,options.ScreenSpaceGate,options.UseSharedColumnCache,
|
|
cameraStepVoxels,options.AuditUniformBlockProofs,options.ProfileLodWork,
|
|
options.RegionCrossing,options.AuditTileShapeReadiness,
|
|
options.DiagnosticSlowShapeCompileMs);
|
|
}
|