build: VoxelForge compiles in Unreal 5.7 on Linux (L65); Linux-only Unreal trace timing fields

Linux UE builds failed on the Core wrapper module: the Linux-only PerModuleInline.gen.cpp saw Standalone/Compat
shadow headers instead of the engine's, and WITH_EDITOR was redefined under -Werror. Compat headers now forward
to the engine headers with include_next for generated Linux module TUs (canonical Core TUs opt into the Compat
definitions via CoreNamespacePreamble.h); CoreMinimal.h undefines WITH_EDITOR first. VoxelForgeCore.Build.cs
enables that forwarding and AVX2 on Linux only; VoxelForge.Build.cs disables Unity on Linux only. Portability:
std::int64_t consistently in VoxelContentManager.cpp; grouped &&/|| in VoxelRedefinedDensityField.cpp. Linux-only
trace fields split Core generateTile / mesh copy / RMC stream build. Standalone Clang and GCC whole-view hashes
are unchanged vs 3202193. The Unreal spawn trace is blocked by the owner's new assets (SW route sweep fails).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-26 19:19:07 +01:00
1 parent e157847509
commit 47148e0a0d
47 files changed
+389 -43

No files matched your search

@@ -241,10 +241,10 @@ static std::vector<VoxelForgeCore::WorldAssemblyFeatureQueryV1> VF_ContentFeatur
{
using namespace VoxelForgeCore;
constexpr double Q = WorldAssemblySubvoxelsPerVoxel;
const std::array<int64,3> Min{static_cast<int64>(std::floor(MinX*Q)),
static_cast<int64>(std::floor(MinY*Q)),static_cast<int64>(std::floor(MinZ*Q))};
const std::array<int64,3> Max{static_cast<int64>(std::ceil(MaxX*Q)),
static_cast<int64>(std::ceil(MaxY*Q)),static_cast<int64>(std::ceil(MaxZ*Q))};
const std::array<std::int64_t,3> Min{static_cast<std::int64_t>(std::floor(MinX*Q)),
static_cast<std::int64_t>(std::floor(MinY*Q)),static_cast<std::int64_t>(std::floor(MinZ*Q))};
const std::array<std::int64_t,3> Max{static_cast<std::int64_t>(std::ceil(MaxX*Q)),
static_cast<std::int64_t>(std::ceil(MaxY*Q)),static_cast<std::int64_t>(std::ceil(MaxZ*Q))};
std::vector<WorldAssemblyFeatureQueryV1> Queries;
if (Surface)
if (const auto* Plan = Surface->FindPlan(StrateIndex))
@@ -2590,8 +2590,8 @@ static float EvaluateInternal(const UVoxelGenerator& Generator,
{
EnsurePlan(Generator);
}
const bool bChunkResolved = Context != nullptr && Context->bChunkResolved
|| ParameterizedContext != nullptr && ParameterizedContext->bChunkResolved;
const bool bChunkResolved = (Context != nullptr && Context->bChunkResolved)
|| (ParameterizedContext != nullptr && ParameterizedContext->bChunkResolved);
const FIntVector Chunk = Context != nullptr && Context->bChunkResolved
? Context->Chunk
: ParameterizedContext != nullptr && ParameterizedContext->bChunkResolved
@@ -297,7 +297,11 @@ void RecordTile(const FTileSample& Sample)
"\"submitted_t_s\":%s,\"worker_start_t_s\":%s,\"worker_end_t_s\":%s,\"worker_thread_id\":%u,"
"\"verdict\":%d,\"proof\":%d,\"empty\":%d,\"vertices\":%d,\"triangles\":%d,\"geometry_bytes\":%llu,"
"\"request_to_apply_s\":%s,\"queue_wait_s\":%s,\"worker_queue_s\":%s,\"result_queue_s\":%s,\"worker_task_s\":%s,"
"\"generation_s\":%s,\"classify_s\":%s,\"mesh_s\":%s,\"stream_s\":%s,\"apply_s\":%s"),
"\"generation_s\":%s,"
#if PLATFORM_LINUX
"\"core_generate_s\":%s,\"mesh_copy_s\":%s,\"rmc_stream_build_s\":%s,"
#endif
"\"classify_s\":%s,\"mesh_s\":%s,\"stream_s\":%s,\"apply_s\":%s"),
Sample.TileX, Sample.TileY, Sample.TileZ,
Sample.Level, Sample.WorkPriority,
static_cast<unsigned long long>(Sample.RequestOrdinal),
@@ -312,8 +316,12 @@ void RecordTile(const FTileSample& Sample)
static_cast<unsigned long long>(Sample.GeometryBytes),
*Number(Sample.RequestToApplySeconds), *Number(Sample.QueueWaitSeconds),
*Number(Sample.WorkerQueueSeconds), *Number(Sample.ResultQueueSeconds),
*Number(Sample.WorkerTaskSeconds),
*Number(Sample.GenerationSeconds), *Number(Sample.ClassifySeconds),
*Number(Sample.WorkerTaskSeconds), *Number(Sample.GenerationSeconds),
#if PLATFORM_LINUX
*Number(Sample.CoreGenerateSeconds), *Number(Sample.MeshCopySeconds),
*Number(Sample.StreamBuildSeconds),
#endif
*Number(Sample.ClassifySeconds),
*Number(Sample.MeshSeconds), *Number(Sample.StreamSeconds), *Number(Sample.ApplySeconds)));
}
+29
View File
@@ -9960,6 +9960,9 @@ bool AVoxelWorld::ApplyTileResult(FChunkResult& Result)
Sample.QueueWaitSeconds = WorkerQueueSeconds + ResultQueueSeconds;
Sample.WorkerTaskSeconds = WorkerTaskSeconds;
Sample.GenerationSeconds = GenerationSeconds;
Sample.CoreGenerateSeconds = Result.CoreGenerateSeconds;
Sample.MeshCopySeconds = Result.MeshCopySeconds;
Sample.StreamBuildSeconds = Result.StreamBuildSeconds;
Sample.ClassifySeconds = Result.ClassifySeconds;
Sample.MeshSeconds = Result.MeshSeconds;
Sample.StreamSeconds = Result.StreamSeconds;
@@ -13235,6 +13238,11 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority
Result.WorkPriority = WorkPriority;
Result.GenerationStartCycles = FPlatformTime::Cycles64();
Result.GenerationOrdinal = NextStreamingGenerationOrdinal.fetch_add(1, std::memory_order_relaxed) + 1;
#if PLATFORM_LINUX
const bool bMeasureWorkerPhases = VoxelForgeStartupTrace::IsActive();
#else
constexpr bool bMeasureWorkerPhases = false;
#endif
auto EnqueueObsolete = [&]()
{
@@ -13290,7 +13298,14 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority
FReadScopeLock Lock(State->WorldLock);
if (State->World)
{
const uint64 CoreGenerateStartCycles = bMeasureWorkerPhases
? FPlatformTime::Cycles64() : 0;
CoreMesh = State->World->generateTile(CoreKey, Options, CoreError);
if (CoreGenerateStartCycles != 0)
{
Result.CoreGenerateSeconds = FPlatformTime::ToSeconds64(
FPlatformTime::Cycles64() - CoreGenerateStartCycles);
}
}
}
Result.GenerationEndCycles = FPlatformTime::Cycles64();
@@ -13332,6 +13347,8 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority
if (!Result.bEmpty)
{
const uint64 MeshCopyStartCycles = bMeasureWorkerPhases
? FPlatformTime::Cycles64() : 0;
FVoxelMeshData MeshData;
MeshData.Vertices.Reserve(Result.NumVertices);
MeshData.Normals.Reserve(Result.NumVertices);
@@ -13352,8 +13369,20 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority
MeshData.NumSurfaceVertices = static_cast<int32>(CoreMesh->groups.surfaceVertexCount);
MeshData.NumCeilingTriangles = Result.NumCeilingTriangles;
MeshData.NumSkirtTriangles = Result.NumSkirtTriangles;
if (MeshCopyStartCycles != 0)
{
Result.MeshCopySeconds = FPlatformTime::ToSeconds64(
FPlatformTime::Cycles64() - MeshCopyStartCycles);
}
const uint64 StreamBuildStartCycles = bMeasureWorkerPhases
? FPlatformTime::Cycles64() : 0;
Result.Streams = MakeShared<RealtimeMesh::FRealtimeMeshStreamSet>();
BuildTileStreamSet(*Result.Streams, MeshData);
if (StreamBuildStartCycles != 0)
{
Result.StreamBuildSeconds = FPlatformTime::ToSeconds64(
FPlatformTime::Cycles64() - StreamBuildStartCycles);
}
}
Result.GenerationEndCycles = FPlatformTime::Cycles64();
if (Cancellation->bObsolete.load(std::memory_order_acquire)
@@ -35,6 +35,9 @@ namespace VoxelForgeStartupTrace
double ResultQueueSeconds = 0.0;
double WorkerTaskSeconds = 0.0;
double GenerationSeconds = 0.0;
double CoreGenerateSeconds = 0.0;
double MeshCopySeconds = 0.0;
double StreamBuildSeconds = 0.0;
double ClassifySeconds = 0.0;
double MeshSeconds = 0.0;
double StreamSeconds = 0.0;
+4
View File
@@ -145,6 +145,10 @@ struct FChunkResult
// per-tile profiling remains opt-in.
uint64 GenerationStartCycles = 0;
uint64 GenerationEndCycles = 0;
// Optional phase timings recorded only while the bounded startup trace is active.
double CoreGenerateSeconds = 0.0;
double MeshCopySeconds = 0.0;
double StreamBuildSeconds = 0.0;
uint64 ApplyStartCycles = 0;
EVoxelTileWorkPriority WorkPriority = EVoxelTileWorkPriority::Horizon;
// Ordinals make admitted order and actual worker start order auditable across MPSC results.
+7
View File
@@ -7,6 +7,13 @@ public class VoxelForge : ModuleRules
{
public VoxelForge(ReadOnlyTargetRules Target) : base(Target)
{
if (Target.Platform == UnrealTargetPlatform.Linux)
{
// Test translation units have independent anonymous-namespace helpers that collide in
// Linux Unity batches. Keep Linux compilation one source per TU; Windows remains unchanged.
bUseUnity = false;
}
// PCH = Precompiled Headers - speeds up compilation
// UseExplicitOrSharedPCHs is the modern recommended setting
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
@@ -39,6 +39,13 @@ public class VoxelForgeCore : ModuleRules
PublicDependencyModuleNames.Add("Core");
CppStandard = CppStandardVersion.Cpp20;
if (Target.Platform == UnrealTargetPlatform.Linux)
{
// The compatibility include directory contains Unreal-shaped placeholders. On Linux,
// let generated module TUs pass those names through to UE while Core shims opt in.
PrivateDefinitions.Add("VFCORE_COMPAT_FORWARD_HEADERS=1");
MinCpuArchX64 = MinimumCpuArchitectureX64.AVX2;
}
// Canonical Standalone code predates UE's stricter warning defaults; keep this narrow to legal local shadowing.
CppCompileWarningSettings.ShadowVariableWarningLevel = WarningLevel.Off;
FPSemantics = FPSemanticsMode.Precise;