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
@@ -23,9 +23,44 @@ changed.
|
||||
tile to `World::generateTile`. Shape-world `--stream-benchmark`, `--stream-pipeline`, edit,
|
||||
audit, and `--benchmark-level` runs use the Core world. Explicit evaluator and owner-comparison
|
||||
modes retain the compatibility generator only as the comparison side of those diagnostics.
|
||||
- The build manifest compiles the copied CPU generator and mesher with the private compatibility
|
||||
headers under `Compat`. Those headers and their Unreal-shaped stand-ins are implementation
|
||||
details. They are absent from the public include tree and public API.
|
||||
- The build compiles the copied CPU generator and mesher with the private compatibility headers
|
||||
under `Compat`. Those headers and their Unreal-shaped stand-ins are implementation details. They
|
||||
are absent from the public include tree and public API.
|
||||
|
||||
## Implementation namespace and Unreal link safety
|
||||
|
||||
The public `VoxelForgeCore.h` surface contains only standard C++ declarations. The copied
|
||||
generator, mesher, and compatibility implementation compile under `vfcore::detail`, so engine
|
||||
symbols such as `FVector`, `TArray`, `FMath`, and `UObject`-shaped stand-ins do not acquire the same
|
||||
linker names as Unreal's definitions. `Core/src/VoxelForgeCore.cpp` owns the public API boundary;
|
||||
it opens `vfcore::detail` only around its private implementation includes, then defines the
|
||||
`VoxelForgeCore` API outside that namespace.
|
||||
|
||||
For each non-boundary source in `Core/core_sources.txt`, `Build.ps1` writes a one-source shim under
|
||||
`Build/VoxelForgeCore/wrappers`. The shim includes `CoreNamespacePreamble.h` before opening
|
||||
`vfcore::detail`, then includes the canonical source path from the manifest. The preamble loads
|
||||
the standard/platform headers and stateless JSON parser before namespace entry, preventing system
|
||||
declarations from being accidentally nested in `vfcore::detail`. The `VoxelForgeCore.cpp` row is
|
||||
compiled directly because it sets up its own public/private namespace boundary. Keep one
|
||||
implementation source per shim.
|
||||
|
||||
`Compat` still defines Unreal-shaped types and a few Unreal-named macros for the copied code, but
|
||||
those declarations live in private implementation translation units only. The UBT module must
|
||||
disable unity builds and PCHs for these shims, and must not force-include Unreal headers into
|
||||
them. This keeps compatibility macros local to one translation unit. Normal plugin adapter
|
||||
translation units may include `CoreMinimal.h` and the public `VoxelForgeCore.h` together; the
|
||||
public header does not include any compatibility header or Unreal declaration.
|
||||
|
||||
`Build.ps1` runs `Core/CheckCoreSymbols.ps1` on the completed static library. The check invokes
|
||||
`dumpbin /SYMBOLS`, derives copied Unreal-style type names from `Compat`, `Source`, and `Core/src`,
|
||||
and fails on an unqualified global occurrence. It also fails closed if `dumpbin` returns too little
|
||||
symbol data to inspect. Rebuilding the `557f6aa` manifest directly and running the same checker
|
||||
found 16,255 unqualified Unreal-style type symbols; the namespaced build checks 177,569
|
||||
symbol-table lines against 370 type names with no violations. The baseline and current logs are
|
||||
retained in `Core/verification/link_safety_557f6aa_final.log` and
|
||||
`Core/verification/link_safety_final.log`. `Core/verification/UnrealHeaderCoexistence.cpp` was
|
||||
also compiled against the installed Unreal 5.7 `CoreMinimal.h` and the public header; see
|
||||
`Core/verification/unreal_header_smoke_final.log`.
|
||||
|
||||
## API and ownership
|
||||
|
||||
@@ -53,22 +88,46 @@ cancellation/version policy. Every client must apply the same sequence and brush
|
||||
|
||||
## Unreal integration: UBT module
|
||||
|
||||
Add a `VoxelForgeCore` runtime module to the plugin. Its `Build.cs` sets
|
||||
`CppStandardVersion.Cpp20`, exports only `Standalone/Core/include`, and keeps these private include
|
||||
roots available to the core implementation:
|
||||
Add a `VoxelForgeCore` runtime module to the plugin and make the existing `VoxelForge` module depend
|
||||
on it. Its `Build.cs` sets C++20, exports only `Standalone/Core/include`, and keeps the Standalone
|
||||
root plus these private include roots available to the core implementation:
|
||||
|
||||
- `Standalone`
|
||||
- `Standalone/Core/src`
|
||||
- `Standalone/Compat`
|
||||
- `Standalone/Source`
|
||||
- `Standalone/Source/VoxelForge/Public`
|
||||
- `Standalone/Source/VoxelForge/Private`
|
||||
|
||||
Set `PCHUsage = PCHUsageMode.NoPCHs` and `bUseUnity = false` for the Core module. For example:
|
||||
|
||||
```csharp
|
||||
string PluginRoot = Path.GetFullPath(Path.Combine(ModuleDirectory, "../.."));
|
||||
string Standalone = Path.Combine(PluginRoot, "Standalone");
|
||||
PublicIncludePaths.Add(Path.Combine(Standalone, "Core", "include"));
|
||||
PrivateIncludePaths.AddRange(new[] {
|
||||
Standalone,
|
||||
Path.Combine(Standalone, "Core", "src"),
|
||||
Path.Combine(Standalone, "Compat"),
|
||||
Path.Combine(Standalone, "Source"),
|
||||
Path.Combine(Standalone, "Source", "VoxelForge", "Public"),
|
||||
Path.Combine(Standalone, "Source", "VoxelForge", "Private")
|
||||
});
|
||||
CppStandard = CppStandardVersion.Cpp20;
|
||||
PCHUsage = PCHUsageMode.NoPCHs;
|
||||
bUseUnity = false;
|
||||
```
|
||||
|
||||
UBT discovers translation units under a module's `Source` tree. Add one thin `.cpp` include shim per
|
||||
row of `Core/core_sources.txt`, with each shim including exactly one canonical source file by a
|
||||
relative path into `Standalone`. Keeping one included source per shim preserves the translation
|
||||
unit boundaries used by `Build.ps1`. A manifest check in the UBT module should fail when a manifest
|
||||
row lacks a shim or a shim names a different file. Do not copy implementation files into the
|
||||
module. The standalone and UBT builds then compile the same source bytes.
|
||||
path rooted at the private `Standalone` include path. For every implementation row except
|
||||
`Core/src/VoxelForgeCore.cpp`, the shim includes `CoreNamespacePreamble.h`, opens
|
||||
`namespace vfcore::detail`, then includes that one source. The special API row gets a shim that
|
||||
includes `Core/src/VoxelForgeCore.cpp` directly; that source establishes its own namespace
|
||||
boundary. Keeping one included source per shim preserves the translation-unit boundaries used by
|
||||
`Build.ps1`. A manifest check in the UBT module should fail when a row lacks a shim, a shim names a
|
||||
different file, or an extra shim exists. Do not copy implementation files into the module. The
|
||||
standalone and UBT builds then compile the same canonical source bytes.
|
||||
|
||||
The existing `VoxelForge` module owns the adapter and calls the new module. Its adapter runs on the
|
||||
game thread, resolves soft references and asset defaults, preserves array order, and serializes
|
||||
@@ -113,22 +172,40 @@ creation, or rendering into the library.
|
||||
|
||||
## Acceptance record
|
||||
|
||||
The retained Round 11 executable is the reference at checkout `631dd57`. The final Core build
|
||||
matched its 11 hash rows (full detail, whole view and LOD0–8) at both W1 and W8. It retained the
|
||||
5,642/5,642 route audit, passed the shape/look and far-survival audits, and the damaged-shell control
|
||||
still reports 512 removed triangles, 16 missing boundary surfaces, 16 holes, and exit 14. Six
|
||||
fixed 1280×800 captures compare byte-for-byte with the Round 11 references. The final single-tile
|
||||
The `557f6aa` commit is the strict output baseline. The rebuilt namespaced Core matches all 11
|
||||
full-detail, whole-view and LOD0–8 hash rows at W1 and W8, with W1/W8 parity. The fresh records are
|
||||
`Core/verification/last_standard_hash_w1.stdout.log`,
|
||||
`Core/verification/last_standard_hash_w8.stdout.log`, and
|
||||
`Core/verification/final_rebuilt_hash_parity.log`.
|
||||
|
||||
The look and shape audits pass, and walkability remains 5,642/5,642. The dedicated passage-camera
|
||||
detail audit passes at 13,271 passage samples with a detail ratio of 1.152. Far survival passes
|
||||
with 7,200 surfaces, zero missing surfaces or holes, and 10,976 far connectors. The damaged-shell
|
||||
control removes 512 triangles, reports 16 missing boundary surfaces and 16 holes, and exits 14.
|
||||
The final rebuilt logs are `Core/verification/final_rebuilt_shape_audit.stdout.log`,
|
||||
`Core/verification/final_rebuilt_passage_camera_audit.stdout.log`,
|
||||
`Core/verification/final_rebuilt_far_survival.stdout.log`, and
|
||||
`Core/verification/final_rebuilt_bad_shell_control.stdout.log`.
|
||||
|
||||
The six fixed 1280×800 views were recaptured from the final rebuilt viewer and compare byte-for-byte
|
||||
with the prior Core captures. Their images are `Core/verification/core_final_rebuild_*.png`; the SHA-256
|
||||
results are in `Core/verification/final_rebuilt_capture_parity.log`. The single-tile
|
||||
`--shape-world --benchmark-level=0` path reports `generator=VoxelForgeCore`.
|
||||
|
||||
The final no-hash, cold W8 direct full-payload benchmark was interleaved
|
||||
reference/core/core/reference with `--stream-benchmark --shape-world --force-generate --workers=8
|
||||
--clip-radius=3`. Process wall means were 1.041 s for the reference (1.035, 1.047) and 1.0245 s
|
||||
for Core (1.037, 1.012), 16.5 ms faster. Each run generated 2,226 tiles with the full 110.90 MiB
|
||||
payload and zero cache hits.
|
||||
The link-safety check demonstrates the failure before the change and the pass after it. Running it
|
||||
on the `557f6aa` library finds 16,255 unqualified Unreal-style symbols; the rebuilt Core library
|
||||
passes after checking 177,569 `dumpbin /SYMBOLS` lines against 370 copied Unreal-style type names.
|
||||
`Core/verification/link_safety_557f6aa_final.log` and
|
||||
`Core/verification/link_safety_final.log` retain the outputs. A smoke translation unit that
|
||||
includes the installed Unreal 5.7 `CoreMinimal.h` and the public `VoxelForgeCore.h` also compiles;
|
||||
see `Core/verification/unreal_header_smoke_final.log`.
|
||||
|
||||
The separate neighborhood-first `--stream-pipeline` benchmark was repeated in eight interleaved
|
||||
processes per build. Whole-view-ready means were 0.887 s for the reference (0.878–0.899 s) and
|
||||
0.894 s for Core (0.880–0.932 s). The 7 ms mean difference is smaller than the 54 ms combined
|
||||
run-to-run range; Core reached the 27-tile neighborhood and 960-tile full-detail milestones at
|
||||
comparable times. Direct benchmark, pipeline, audit, and capture logs are retained in
|
||||
`Core/verification`.
|
||||
**Speed gate: not met.** The no-hash, cold W8 `--stream-pipeline --shape-world --force-generate`
|
||||
check was run in four interleaved baseline/Core pairs, each generating 2,226 tiles and the full
|
||||
110.90 MiB mesh payload with no cache hits. `whole_view_ready` averaged 0.89175 s for the exact
|
||||
`557f6aa` executable and 0.92050 s for the namespaced build, a 28.8 ms (3.2%) regression. Stream
|
||||
wall time was effectively unchanged at 0.46000 s and 0.46025 s; the difference was in shape
|
||||
compilation, including `intervals+signs` averaging 95.7 ms on baseline and 114.9 ms on Core. The
|
||||
raw cold runs are in `Core/verification/final_rebuilt_pipeline_*.stdout.log`. API-only `/Ob3` and
|
||||
`/Ob1` trials also retained hash parity but were slower, so the build is restored to `/O2 /MP8`.
|
||||
The required “no slower” acceptance condition remains outstanding.
|
||||
Reference in new issue
Block a user