standalone: per-tile speed at plugin level, streaming like the game, softer lighting

Cause found by profiling: room/SDF graph-cache churn (exact XY bounds + sample order rebuilt it
constantly). Region grouping (one LOD3 tile: 1,084 -> 229 builds), taller-tile traversal for LOD6
(36,480 -> 12,160), extent-dependent cache slots, lambdas instead of recursive std::function.
Serial ms/tile, 64 nearest tiles per level (before -> after):
  L0 50.4 -> 50.6, L1 112 -> 110, L2 24 -> 22, L3 223 -> 73, L4 269 -> 134, L5 393 -> 127, L6 283 -> 145.
Hashes of all levels unchanged; parity 3,436/3,436 bit-identical.
Full clipmap, 16 workers BelowNormal: full detail 66.6 s, all 12,054 tiles 175 s. In-stream L0 tail is
high (median 83 ms, mean 198 ms, p95 669 ms) vs 51 ms serial.
Streaming: recentre keeps the intersection, generates only missing tiles nearest/finest first;
one crossing = exactly 441 new tiles in 6.1 s, no stale results.
Lighting: normals already come from the density gradient; the striping was the squared headlamp;
broad linear fill + warmer palette. Daytime CPU rule documented in Standalone/README.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-03 06:49:41 +02:00
1 parent 3f300b912a
commit 81b7d6d0ff
24 files changed
+1096 -196

No files matched your search

+69 -2
View File
@@ -8,11 +8,13 @@
#include <bit>
#include <cassert>
#include <chrono>
#include <charconv>
#include <cctype>
#include <cstdarg>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <immintrin.h>
@@ -632,8 +634,73 @@ struct FWriteScopeLock { explicit FWriteScopeLock(FRWLock&L):Lock(L.Mutex){} std
enum EConsoleVariableFlags { ECVF_Default=0, ECVF_SetByCommandline=1, ECVF_SetByCode=2 };
class FAutoConsoleVariableRef { public:FAutoConsoleVariableRef(const char*,int32&,const char*,uint32=0){} FAutoConsoleVariableRef(const char*,float&,const char*,uint32=0){} FAutoConsoleVariableRef(const char*,bool&,const char*,uint32=0){} };
template<class T> class TAutoConsoleVariable { public:TAutoConsoleVariable(const char*,T Default,const char*,uint32=0):Value(Default){}T GetValueOnAnyThread()const{return Value.load();}T GetValueOnGameThread()const{return Value.load();}void Set(T V,uint32=0){Value.store(V);} TAutoConsoleVariable*operator->(){return this;}private:std::atomic<T>Value;};
struct FCommandLine { static const char* Get(){return "";} };
struct FParse { static bool Value(const char*,const char*,int32&){return false;} static bool Value(const char*,const char*,float&){return false;} static bool Value(const char*,const char*,FString&){return false;} static bool Param(const char*,const char*){return false;} };
struct FCommandLine
{
inline static std::string Arguments;
static const char* Get(){return Arguments.c_str();}
static void Set(std::string_view InArguments){Arguments.assign(InArguments);}
};
struct FParse
{
static bool ReadValue(const char* CommandLine,const char* Key,std::string& Out)
{
if(!CommandLine||!Key||!*Key)return false;
const std::string_view Command(CommandLine),Token(Key);
std::size_t Position=0;
while((Position=Command.find(Token,Position))!=std::string_view::npos)
{
const bool bTokenStart=Position==0||Command[Position-1]==' '
||Command[Position-1]=='\t'||Command[Position-1]=='-';
const std::size_t ValueStart=Position+Token.size();
if(bTokenStart&&ValueStart<=Command.size())
{
std::size_t ValueEnd=Command.find_first_of(" \t\r\n",ValueStart);
if(ValueEnd==std::string_view::npos)ValueEnd=Command.size();
if(ValueEnd>ValueStart)
{Out.assign(Command.substr(ValueStart,ValueEnd-ValueStart));return true;}
}
Position+=Token.size();
}
return false;
}
static bool Value(const char* CommandLine,const char* Key,int32& Out)
{
std::string Text;
if(!ReadValue(CommandLine,Key,Text))return false;
const auto Result=std::from_chars(Text.data(),Text.data()+Text.size(),Out);
return Result.ec==std::errc{}&&Result.ptr==Text.data()+Text.size();
}
static bool Value(const char* CommandLine,const char* Key,float& Out)
{
std::string Text;
if(!ReadValue(CommandLine,Key,Text))return false;
char* End=nullptr;Out=std::strtof(Text.c_str(),&End);
return End==Text.c_str()+Text.size();
}
static bool Value(const char* CommandLine,const char* Key,FString& Out)
{
std::string Text;
if(!ReadValue(CommandLine,Key,Text))return false;
Out=FString(Text);return true;
}
static bool Param(const char* CommandLine,const char* Name)
{
if(!CommandLine||!Name||!*Name)return false;
const std::string_view Command(CommandLine),Token(Name);
std::size_t Position=0;
while((Position=Command.find(Token,Position))!=std::string_view::npos)
{
const bool bTokenStart=Position==0||Command[Position-1]==' '
||Command[Position-1]=='\t'||Command[Position-1]=='-';
const std::size_t End=Position+Token.size();
const bool bTokenEnd=End==Command.size()||Command[End]==' '
||Command[End]=='\t'||Command[End]=='\r'||Command[End]=='\n';
if(bTokenStart&&bTokenEnd)return true;
Position=End;
}
return false;
}
};
struct FCrc { static uint32 MemCrc32(const void*Data,int32 Length,uint32 Crc=0){const auto*P=static_cast<const uint8*>(Data);uint32 V=~Crc;for(int32 I=0;I<Length;++I){V^=P[I];for(int J=0;J<8;++J)V=(V>>1)^(0xEDB88320u&static_cast<uint32>(-static_cast<int32>(V&1)));}return ~V;} static uint32 StrCrc32(const char*S,uint32 Crc=0){return MemCrc32(S,static_cast<int32>(std::strlen(S)),Crc);} };
template<class T> using TAtomic = std::atomic<T>;
class FThreadSafeCounter { public:int32 Increment(){return ++Value;}int32 Decrement(){return --Value;}int32 GetValue()const{return Value.load();}void Reset(){Value.store(0);}private:std::atomic<int32>Value{0};};