Skip to content

Claude/engine roadmap 8 kc2c#458

Merged
Krilliac merged 18 commits into
Workingfrom
claude/engine-roadmap-8Kc2c
Apr 11, 2026
Merged

Claude/engine roadmap 8 kc2c#458
Krilliac merged 18 commits into
Workingfrom
claude/engine-roadmap-8Kc2c

Conversation

@Krilliac

Copy link
Copy Markdown
Owner

No description provided.

claude added 2 commits April 11, 2026 03:12
Converts the first Tier 2 graphics orphan utility (GTAOEffect.h,
447 lines, zero callers) into an actively wired render feature.
GTAO is slotted first in PostProcessPass so ambient occlusion
modulates scene lighting at HDR resolution before Bloom extracts
highlights. Mirrors the existing 14-effect pattern: inline pixel
shader literal in CompileEffectShaders, settings accessor pair,
ProcessPass switch case, and a standalone Shaders/HLSL/GTAOPS.hlsl
for offline build-time validation.

Tests: 8 new CPU-reference cases against the real GTAOEffect class
(defaults, init lifecycle, bad-dimensions rejection, open-sky flat
depth, zero-depth early-out, wall-occluder AO, denoiser identity,
HLSL source shape). Total 4370 tests passing on Linux, 0 failures.

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
Sync the Phase I knowledge entry with the earlier draft that was
recovered by the working tree. Content is equivalent — same items,
same build results, reworded sections.

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aacf3d11e9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

*/
enum class PostProcessPass
{
GTAO, ///< Ground Truth Ambient Occlusion (horizon-based screen-space AO)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add GTAO to post-process toggle plumbing

Adding PostProcessPass::GTAO here introduces a new pass that defaults to disabled (m_passEnabled is zero-initialized) but this commit does not add a way to turn it on through the engine’s existing control path: the only in-repo callers of SetEffectEnabled are the pp_enable/pp_disable command maps in SparkEngine/Source/Core/SubsystemConsoleCommands.cpp (around lines 501-551), and those maps have no gtao entry. In practice, users cannot activate the new pass at runtime, so the feature remains effectively unreachable.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already addressed in Phase J (commit 262325a). Both pp_enable and pp_disable console command maps in SparkEngine/Source/Core/SubsystemConsoleCommands.cpp now include {"gtao", Graphics::PostProcessPass::GTAO} (lines 502 and 540 on the current branch tip), so users can pp_enable gtao / pp_disable gtao from the console. Phase J added the same entry for the new ssaotemporal pass at the same time.


Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

Code Coverage (GCC + lcov)

Utils/MemoryMonitor.h                          |85.7%    14| 0.0%  12|    -    0
Utils/MultiISA.h                               |42.9%    14| 0.0%   6|    -    0
Utils/NetworkHealthMonitor.cpp                 | 113%    15| 0.0%   2|    -    0
Utils/NetworkHealthMonitor.h                   |    -     0|    -   0|    -    0
Utils/OpaqueHandle.h                           | 282%    11| 0.0%  15|    -    0
Utils/ProcessLinux.cpp                         |16.5%   182| 0.0%  28|    -    0
Utils/Profiler.cpp                             |14.2%   113| 0.0%  15|    -    0
Utils/Profiler.h                               |36.4%    33| 0.0%  12|    -    0
Utils/RandomEngine.h                           |29.3%    41| 0.0%  12|    -    0
Utils/Result.h                                 | 100%    29| 0.0%  28|    -    0
Utils/RingBuffer.h                             | 108%    59| 0.0%  64|    -    0
Utils/ScopeGuard.h                             | 142%    36| 0.0%  51|    -    0
Utils/ScopedTimer.h                            |25.0%    12| 0.0%   3|    -    0
Utils/Serializer.h                             | 100%    48| 0.0%  42|    -    0
Utils/SparkConsole.cpp                         |28.5%   144| 0.0%  17|    -    0
Utils/SparkConsole.h                           | 100%     2| 0.0%   2|    -    0
Utils/SparkError.h                             |10.9%    55| 0.0%   6|    -    0
Utils/SplinePath.h                             |    -     0|    -   0|    -    0
Utils/StackTrace.h                             |10.8%    74| 0.0%   8|    -    0
Utils/StateMachine.h                           |54.0%    63| 0.0%  32|    -    0
Utils/StringUtils.h                            |18.1%   116| 0.0%  21|    -    0
Utils/Telemetry.h                              |20.7%   135| 0.0%  22|    -    0
Utils/ThreadDebugger.h                         |11.6%   199| 0.0%  23|    -    0
Utils/ThreadSafeQueue.h                        |27.5%    40| 0.0%  11|    -    0
Utils/TimerManager.h                           |19.8%    96| 0.0%  19|    -    0
Utils/UUID.h                                   |43.2%    37| 0.0%  16|    -    0
Utils/Validate.h                               |    -     0|    -   0|    -    0

[/home/runner/work/SparkEngine/SparkEngine/SparkSDK/Include/Spark/]
IEngineContext.h                               |7300%     1| 0.0%   1|    -    0
ServiceInterfaces.h                            | 200%     3| 0.0%   3|    -    0
Version.h                                      |    -     0|    -   0|    -    0
================================================================================
                                         Total:|28.7% 25650| 0.0%  4k|    -    0

Per-Subsystem Coverage

Subsystem Lines Hit Coverage Threshold Status
AI 2817 734 26.1% 35%
Animation 160 154 96.2% 35%
Audio 0 0 0% 30%
Camera 0 0 0% 40%
Core 2308 1448 62.7% 40%
ECS 190 115 60.5% 40%
Editor 7377 2823 38.3% 25%
GameModules 6244 3132 50.2% 30%
Graphics 8830 4523 51.2% 30%
Networking 3420 2269 66.3% 35%
Physics 0 0 0% 35%
Scripting 0 0 0% 30%
Utils 7688 4864 63.3% 60%

Total: 51.4% (20062/39034 lines)

claude added 2 commits April 11, 2026 05:23
Wire SSAOTemporal, RenderTargetPool, GPUDebugMarkers, and
GPUTimestampQuery into the real PostProcessingPipeline. SSAOTemporal
lands as the 16th post-process pass (variance-clipped AO denoiser
slotted after GTAO); RenderTargetPool is owned per-pipeline and ticked
each frame; every ProcessPass is bracketed by a ScopedGPUEvent for
PIX/RenderDoc captures; per-pass GPU timestamps replace std::chrono
CPU-side measurements when a D3D11 device is attached. Metrics tables
are now static_assert'd against PostProcessPass::Count so future enum
additions can't silently desync. pp_enable/pp_disable console commands
gain gtao + ssaotemporal keywords. 25 new tests
(TestSSAOTemporalFilter, TestPostProcessingPipelinePhaseJ) cover the
CPU reference path and the portable accessor surface; full suite
4395 passed, 0 failed on linux-gcc-release.

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
Rewrite the Phase J summary with fuller per-item detail, test coverage
lists, and a Phase K candidate roadmap. Content-equivalent but more
comprehensive than the original commit.

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
@github-actions

Copy link
Copy Markdown
Contributor

Code Coverage (GCC + lcov)

Utils/MemoryMonitor.h                          |85.7%    14| 0.0%  12|    -    0
Utils/MultiISA.h                               |42.9%    14| 0.0%   6|    -    0
Utils/NetworkHealthMonitor.cpp                 | 113%    15| 0.0%   2|    -    0
Utils/NetworkHealthMonitor.h                   |    -     0|    -   0|    -    0
Utils/OpaqueHandle.h                           | 282%    11| 0.0%  15|    -    0
Utils/ProcessLinux.cpp                         |16.5%   182| 0.0%  28|    -    0
Utils/Profiler.cpp                             |14.2%   113| 0.0%  15|    -    0
Utils/Profiler.h                               |36.4%    33| 0.0%  12|    -    0
Utils/RandomEngine.h                           |29.3%    41| 0.0%  12|    -    0
Utils/Result.h                                 | 100%    29| 0.0%  28|    -    0
Utils/RingBuffer.h                             | 108%    59| 0.0%  64|    -    0
Utils/ScopeGuard.h                             | 142%    36| 0.0%  51|    -    0
Utils/ScopedTimer.h                            |25.0%    12| 0.0%   3|    -    0
Utils/Serializer.h                             | 100%    48| 0.0%  42|    -    0
Utils/SparkConsole.cpp                         |28.5%   144| 0.0%  17|    -    0
Utils/SparkConsole.h                           | 100%     2| 0.0%   2|    -    0
Utils/SparkError.h                             |10.9%    55| 0.0%   6|    -    0
Utils/SplinePath.h                             |    -     0|    -   0|    -    0
Utils/StackTrace.h                             |10.8%    74| 0.0%   8|    -    0
Utils/StateMachine.h                           |54.0%    63| 0.0%  32|    -    0
Utils/StringUtils.h                            |18.1%   116| 0.0%  21|    -    0
Utils/Telemetry.h                              |20.7%   135| 0.0%  22|    -    0
Utils/ThreadDebugger.h                         |11.6%   199| 0.0%  23|    -    0
Utils/ThreadSafeQueue.h                        |27.5%    40| 0.0%  11|    -    0
Utils/TimerManager.h                           |19.8%    96| 0.0%  19|    -    0
Utils/UUID.h                                   |43.2%    37| 0.0%  16|    -    0
Utils/Validate.h                               |    -     0|    -   0|    -    0

[/home/runner/work/SparkEngine/SparkEngine/SparkSDK/Include/Spark/]
IEngineContext.h                               |7300%     1| 0.0%   1|    -    0
ServiceInterfaces.h                            | 200%     3| 0.0%   3|    -    0
Version.h                                      |    -     0|    -   0|    -    0
================================================================================
                                         Total:|28.7% 25832| 0.0%  4k|    -    0

Per-Subsystem Coverage

Subsystem Lines Hit Coverage Threshold Status
AI 2817 734 26.1% 35%
Animation 160 154 96.2% 35%
Audio 0 0 0% 30%
Camera 0 0 0% 40%
Core 2310 1449 62.7% 40%
ECS 190 115 60.5% 40%
Editor 7377 2823 38.3% 25%
GameModules 6244 3134 50.2% 30%
Graphics 9169 4702 51.3% 30%
Networking 3420 2269 66.3% 35%
Physics 0 0 0% 35%
Scripting 0 0 0% 30%
Utils 7688 4864 63.3% 60%

Total: 51.4% (20244/39375 lines)

claude added 11 commits April 11, 2026 05:59
… volumes

Wire the Tier 2 graphics orphan VolumeSystem.h into PostProcessingPipeline
as a live per-pipeline instance. Users create global or local volumes via
pipeline->GetVolumeManager(), set the camera position with SetCameraPosition,
and on each Process() call the blended VolumeStack (exposure compensation,
bloom, color grading, fog) is pushed into the pipeline's effect settings
via the new public ApplyVolumeStack() method.

Only fields whose overrideState was set by a real volume land on the
settings, so hand-authored values survive volume-less frames. K2 fixes a
latent bug in VolumeSystem.h: all four Interpolate methods now propagate
overrideState = true for every field they lerp, which is the correctness
premise ApplyVolumeStack relies on. ColorGradingVolumeComponent::Interpolate
was tightened with a local SPARK_VOLUME_BLEND macro to keep the 13-field
blend readable. VolumeSystem.h also now explicitly includes <memory> for
std::unique_ptr / std::make_unique instead of relying on transitive
inclusion from consumers.

Adds 22 new tests: 11 VolumeManager CPU oracle tests and 11 PhaseK
integration tests against the real pipeline. SparkTests: 4418 passed,
0 failed, 119075 assertions on linux-gcc-release.

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
…hans

L1 wires MeshOptimizer::ComputeACMR into LODManager::GenerateLODChain
(Windows-only) so every generated LOD chain logs the source mesh's
Average Cache Miss Ratio at INFO level. Adds 15 portable tests against
Spark::Graphics::MeshOptimizer directly — the previous coverage via
TestGraphicsIntegration.cpp was a local reimplementation that never
touched the real class, leaving ComputeACMR/OptimizeVertexCache/
OptimizeVertexFetch/GenerateMeshlets effectively untested.

L2 wires BVHAccelerator::Build + FrustumQuery into SceneRenderer::CullAndSort
as a first-level frustum pre-cull. Before L2 both GraphicsEngine::m_bvhAccelerator
and SceneRenderer::m_bvh were declared members with zero callers — pure
scaffolding. Now every frame builds a BVH from the live draw commands
(synthetic unit AABBs around each world position), runs FrustumQuery
against the extracted camera frustum, and short-circuits the existing
per-command point-in-clip loop on the result. Survivors still run the
precise point test, so no mesh visible to the existing logic disappears.
Adds 10 Windows-gated tests covering Build, FrustumQuery culling,
rebuild semantics, and a 50-primitive smoke test.

SparkTests: 4433 passed, 0 failed, 119228 assertions on linux-gcc-release
(+15 from Phase K baseline; the 10 BVH tests only register on Windows).

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
…wAtlas in LightingSystem

Wire two Tier 2 graphics orphans as lifecycle-owned members of
LightingSystem. ReflectionProbeCache schedules static probes to render
once + cache, dynamic probes on a per-frame budget; CachedShadowAtlas
maintains separate dynamic + cached sub-atlases and uses a FNV-1a
state hash to decide whether a static light's shadow map can be reused.

Both orphans are pure CPU so they live outside the SPARK_PLATFORM_WINDOWS
guard. Initialize / Shutdown / BeginFrame / EndFrame hooks land on
both the Windows real impl and the Linux stub path in LightingSystem.cpp
so headless and GPU builds produce consistent state. Update() extracts
the camera world position from the inverse view matrix and feeds the
probe cache; the shadow atlas frame boundary brackets the existing
light culling + shadow map update work.

Adds 29 portable tests: 16 TestReflectionProbeCache covers register/
unregister, budget scheduling, static vs dynamic cache, LRU eviction,
invalidation, and console status; 13 TestCachedShadowAtlas covers
request routing, cache-hit detection via state hash, forceUpdate
bypass, invalidation, and dynamic/cached atlas routing.

SparkTests: 4461 passed, 0 failed, 1 warned (pre-existing known-flaky),
119289 assertions on linux-gcc-release (+29 tests, +61 assertions from
Phase L baseline).

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
…g in PostProcessingPipeline

N1 wires RTHandleSystem as a portable per-pipeline member. Unlike most
"Graphics utility" orphans this one has no D3D11 dependency — it's pure
CPU allocation metadata (reference size, per-handle scale factors, max-
history bookkeeping) with format as a raw uint32_t. That lets the
member live outside the SPARK_PLATFORM_WINDOWS guard and makes the
allocate / resize / dynamic-scale paths fully testable on every CI
platform. Initialize follows the pipeline's reference viewport,
Resize() forwards the new size via SetReferenceSize so every allocated
handle updates its current dimensions, Shutdown clears all handles.

N2 wires ConstantBufferRing as a Windows-only per-pipeline member.
Initialize allocates a 2 MB dynamic ID3D11Buffer when a device is
attached; BeginFrame brackets Process() alongside GPUTimestampQuery
and opens a WRITE_DISCARD map; EndFrame unmaps. Per-pass sub-allocation
is deferred — the existing m_constantBuffer per-pass Map/Unmap path
still runs. Lifecycle-only activation gives future sub-allocation
callers a zero-churn landing zone. Exposes portable
GetConstantBufferRingCapacity / GetConstantBufferRingPeakUsage
accessors that return 0 on non-Windows so UI panels don't special-case
the platform.

Adds 29 new tests: 14 TestRTHandleSystem + 2 BufferedRTHandle portable
CPU tests, 9 Windows-gated TestConstantBufferRing tests covering the
uninitialised-state contract and input rejection paths, and 6 portable
TestPostProcessingPipelinePhaseN integration tests. SparkTests: 4483
passed, 0 failed, 1 warned (pre-existing known-flaky), 119366 assertions
on linux-gcc-release (+77 from Phase M baseline).

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
Wire Spark::Graphics::ShaderVariantSystem as a per-instance member of
the Shader class with Initialize/Shutdown hooks on both the Windows
real impl and the Linux stub path. Every Shader now carries its own
keyword registry, variant key state, and preprocessor-define
resolution. New public GetVariantSystem() accessor pair exposes the
system to the material / hot-reload / disk-cache layers that already
reference it in @see comments.

The Shader class lives in the global Spark namespace (not
Spark::Graphics), so member declarations + accessor signatures use
explicit Spark::Graphics:: qualification — same pattern as Phase M's
LightingSystem wiring.

Adds 21 portable tests against the real class covering lifecycle,
keyword registration (including the kMaxKeywords=64 ceiling), keyword
groups with default indices, keyword state management, variant key bit
operations, global+material variant resolution, define list
generation, ShaderFeature stripping, ShouldCompileVariant feature
gating, pre-warming, and console status formatting. Previous coverage
in TestGraphicsIntegration.cpp was 3 thin smoke tests against bit math
only — the real class lifecycle + registration + resolution paths had
zero coverage before Phase O.

SparkTests: 4505 passed, 0 failed, 0 warned, 119495 assertions on
linux-gcc-release (+21 tests, +129 assertions over Phase N baseline).
Even the normally-flaky LoadTest_Severe_EntityFlood passed cleanly.

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
…erialSystem

Wire Spark::Graphics::PersistentMaterialCBManager as a per-instance
member of Spark::MaterialSystem with Initialize (4096 materials ×
256-byte slots = 1 MB shadow buffer) / Shutdown / BeginFrame hooks.
Unlike LightingSystem and Shader, MaterialSystem's Initialize and
Shutdown bodies are shared across Windows and Linux, so a single hook
site at each lifecycle point wires both platforms.

Every MaterialSystem now owns a live persistent CB manager with FNV-1a
hash-based dirty tracking — materials only land on the GetDirtySlots
list when their uploaded data actually changes. BeginFrame() advances
the internal frame counter so MaterialCBSlot::lastUpdatedFrame stamps
reflect the real render frame index. A future GPU-side companion can
read the shadow via GetMaterialData(id) and upload only dirty
sub-ranges.

New public GetPersistentMaterialCB() accessor pair exposes the
manager to downstream material bind / shader compilation / draw
command layers. MaterialSystem lives in the global Spark namespace
so the member declaration and accessor signatures use explicit
Spark::Graphics:: qualification — same pattern as Phases M (LightingSystem)
and O (Shader).

Adds 19 portable tests covering lifecycle (including 16-byte CB-size
alignment), registration (contiguous slot allocation, idempotent
duplicates, overflow rejection), update + hash detection (no-op on
identical data, dirty on divergence, safe smaller-than-slot writes),
dirty list drain, frame-counter stamping, and console status. Full
suite: 4523 passed, 0 failed, 1 warned (pre-existing known-flaky
LoadTest), 119543 assertions on linux-gcc-release (+19 tests, +48
assertions over Phase O baseline).

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
…er in GraphicsEngine

Wire the bundled IDenoiser / SoftwareDenoiser plugin pair as a
std::unique_ptr<IDenoiser> member of Spark::Graphics::GraphicsEngine.
The SoftwareDenoiser is a joint bilateral filter with optional
albedo + normal guide weighting — pure CPU, no external SDK, works
on every platform. A future OIDN / OptiX / neural implementation can
swap the pointee inside GraphicsEngine::Initialize without any
header reshuffling because the member type is the abstract interface.

Lifecycle hooks on both the Windows real impl and the Linux stub
path (GraphicsEngine.cpp has two full Initialize/Shutdown branches;
Phase Q mirrors the denoiser allocation + teardown on both so
headless builds see consistent state). Initial settings default to
enabled=false so no CPU work runs until a future RT pass toggles it
on — the activation is lifecycle-only, matching Phase N's
ConstantBufferRing pattern.

New public GetDenoiser() / GetDenoiserBackend() accessors expose
the denoiser to downstream callers. GetDenoiserBackend() needs a
matching body in both Windows and Linux branches of the .cpp file
(documented in the Phase Q knowledge entry as a repeatable gotcha).

Adds 14 portable tests covering settings defaults, lifecycle,
constant-field passthrough, noisy-input variance reduction (using a
hash-based pseudo-random pattern instead of a checkerboard, which
defeats joint bilateral filtering), optional albedo + normal guides,
polymorphic dispatch via the IDenoiser base class, quality presets,
temporal settings, and deterministic repeated Execute() calls.

One test-framework gotcha fixed: EXPECT_EQ streams operands to
std::ostream which doesn't compile for enum class values. Four call
sites cast to int to work around it; documented in the knowledge
entry for future enum-class tests.

SparkTests: 4537 passed, 0 failed, 1 warned (pre-existing known-
flaky LoadTest), 120154 assertions on linux-gcc-release (+14 tests,
+611 assertions over Phase P baseline — the assertion bump reflects
per-pixel checks in the denoise tests).

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
…delete resolved)

Audit decision: WIRE, not delete. The April 10 audit flagged
UICompositor as "may be superseded by Engine/UI" but a grep across
Engine/UI/ found zero references to UICompositor, CompositeOp,
BeginComposite, or any related symbols. The two systems are
complementary — UISystem manages the widget hierarchy, layout, and
input; UICompositor manages the composition stack for nested widget
effects (blur, mask, opacity) and pools the intermediate render
target metadata those effects need. Activation gives Spark::UI::UISystem
a per-instance Spark::Graphics::UICompositor member with lifecycle
hooks on Initialize / OnResize / Render.

Initialize clamps non-positive screen dimensions to 1 so the
compositor has a valid reference size even when the caller passes
garbage. OnResize calls Initialize again (it doubles as reset) so
the pool drops any in-flight composite levels and re-aligns metadata
with the new screen size. Render calls BeginFrame *before* the
visibility check so the 10-frame idle reclaim path drains even when
the UI is hidden — otherwise SetVisible(false) would leak pool
memory indefinitely.

Also fixes a latent hidden-include bug: UICompositor.h uses
std::remove_if without including <algorithm>. The header had zero
direct consumers before Phase R so transitive includes silently
saved it; adding UISystem.h as the first real consumer would have
failed the build without the fix. One-line include add.

Adds 20 portable tests: 13 TestUICompositor covering lifecycle,
push/pop, max-stack-depth (8) and max-pool-size (16) limits, same-
size pool reuse, different-size pool growth, frame reclaim (15
idle frames drain the pool), mid-frame stack clear, and console
status. 7 TestUISystemPhaseR integration tests cover the UISystem
lifecycle hooks — Initialize follows, non-positive dimensions clamp,
push/pop via the accessor, Render reclaims stale entries across 15
frames, Render clears leftover stacks, OnResize re-initialises, and
OnResize handles zero dimensions.

SparkTests: 4557 passed, 0 failed, 1 warned (pre-existing known-
flaky LoadTest), 120236 assertions on linux-gcc-release (+20 tests,
+82 assertions over Phase Q baseline).

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
…icsEngine

Wire Spark::Graphics::NoiseGraph as a std::unique_ptr member of
GraphicsEngine, default-initialised with a SimplexNode as the
output. The 749-line header ships Simplex, Perlin, Cellular, FBM,
DomainWarp, and Combiner nodes with runtime SIMD detection
(Scalar/SSE2/AVX2, compile-time preprocessor-based so effectively
zero-cost), a batch evaluation path that processes 4 samples per
iteration, and the NoiseGraph owning container.

Lifecycle hooks on both the Windows real impl and the Linux stub
path — GraphicsEngine.cpp has two full Initialize/Shutdown branches
and Phase S mirrors the allocation + teardown on both so headless
builds see the same default Simplex output. The NoiseGraph is owned
via unique_ptr because its internal m_outputNode raw pointer aliases
into the owned std::vector<std::unique_ptr<NoiseNode>>; heap
ownership keeps that alias stable across any future GraphicsEngine
copy or std::vector<GraphicsEngine> resize.

New public accessors: GetProceduralNoise() returns the live
NoiseGraph pointer (terrain / foliage scatter / decoration systems
can Evaluate or AddNode through it), and GetProceduralNoiseSIMDLevel()
returns the runtime-detected kernel level. Both have matching
Windows + Linux bodies (same duplication pattern as Phase Q's
GetDenoiserBackend).

Adds 28 portable tests covering SIMD detection (level range,
name strings, graph-level accessor consistency), Simplex / Perlin
/ Cellular node determinism and type reporting, FBM octave /
lacunarity / gain accessors + determinism, DomainWarp amplitude
round-trip + null-child safety, Combiner Add/Multiply/Min/Max ops
+ SetOp round-trip + null-child safety, batch evaluation
consistency (non-multiple-of-4 counts exercise both the unrolled
loop and the scalar remainder), FBM batch vs single matching,
NoiseGraph empty-graph evaluation, Add/SetOutputNode routing,
batch path, and multi-node ownership.

SparkTests: 4587 passed, 0 failed, 0 warned (even the normally-
flaky LoadTest_Severe_EntityFlood passed cleanly), 120370
assertions on linux-gcc-release (+28 tests, +134 assertions over
Phase R baseline).

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
…icsEngine

Wire Spark::Graphics::VCTSystem as a std::unique_ptr member of
GraphicsEngine, initialised with a small 32³ voxel grid (~130 KB)
and enabled=false by default. Closes the last major Tier 2 graphics
orphan catalogued in the April 10 audit — Phases I→T now cover 18
orphans activated on this branch.

Scope surprise: Phase S's knowledge entry parked VCT as "multi-
session scope" assuming it needed a real GI render pipeline. Reading
the source showed VoxelConeTracing.h is fully portable CPU code —
VoxelGrid uses std::vector<uint8_t> for its data + mip chain, and
VCTSystem's four-stage pipeline (BeginVoxelization → Inject →
EndVoxelization → TraceDiffuse/Specular) runs entirely on CPU with
no D3D11, no compute shaders, no external SDK. That made Phase T a
regular-sized activation, not a parked multi-session block.

Lifecycle hooks on both the Windows real impl and the Linux stub
path (GraphicsEngine.cpp has two full Initialize/Shutdown branches).
Default settings set enabled=false so the VCT pipeline does zero
per-frame work until a future GI pass opts in — same "alive but
idle" posture Phase Q's denoiser activation uses. Callers who want
full 128³ resolution (~9 MB) can re-initialise via
GetVCTSystem()->Initialize({.voxelResolution = 128, ...}).

Adds 24 portable tests covering VCTSettings defaults, VoxelGrid
lifecycle + mip count + console status, light injection in-bounds
/ out-of-bounds / clear, cone tracing (empty grid, light
accumulation, wall occlusion, step multiplier), mip chain
idempotency, VCTSystem init/shutdown + default resolution +
settings round-trip, voxelization pipeline (Begin/Inject/End +
intensity scaling), diffuse/specular cone tracing (cone count,
roughness widening, empty grid), console status formatting (ON/OFF),
and reinitialise-growth cycle.

SparkTests: 4611 passed, 0 failed, 0 warned (even the normally-
flaky LoadTest_Severe_EntityFlood passed cleanly), 120441
assertions on linux-gcc-release (+24 tests, +71 assertions over
Phase S baseline).

Tier 2 graphics orphan pool is now exhausted. The Phase T knowledge
entry sketches three roadmap directions for Phase U+:
1. Tier 3 / Tier 4 orphans from the non-Graphics audit entries
2. Quality improvements on I→T "lifecycle only" activations
3. Start a new theme (shader hot-reload, RHI backend parity, or
   editor panel activation)

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
…session

Phase T exhausted the Tier 2 graphics orphan pool (18 orphans
activated across Phases I→T). This commit documents the Phase U+
plan for direction 3 from the Phase T roadmap: start a new theme
now that the Tier 2 pool is closed.

The plan sketches three candidate themes in priority order:

1. Theme 3A — Shader hot-reload surface (ShaderHotReload,
   ShaderDiskCache, ShaderCrossCompiler). Three orphans on one
   subsystem, all portable, clear activation pattern matching
   Phase O. Tightest fit — recommended as Phase U / V / W.

2. Theme 3B — RHI backend parity (RHIHandlePool,
   TransientBufferAllocator activated in Vulkan / D3D12 / OpenGL
   / NullRHIDevice). Larger scope — 4 phases, many Windows-only
   tests. Requires per-backend survey before phase planning.

3. Theme 3C — Editor panel activation. Revisits Tier 4 audit
   entries that Phases A–G didn't touch. Scope depends on a
   SparkEditor/Source/Panels/ survey against EditorPanelFactory.

Plan includes a full "Playbook" section capturing the reusable
I→T rhythm: source-read before scoping, portability check,
namespace qualification for global-Spark classes, lifecycle hooks
on both Windows + Linux branches, default-to-idle for opt-in
features, test-against-real-class, EXPECT_EQ enum-class cast
workaround, build/test/format cycle, one-phase-per-commit.

No code changes in this commit — the plan is deferred to a future
session. When resumed, that session should read the Phase T
knowledge entry for the current state, then this plan, then pick
Phase U (ShaderHotReload) and follow the playbook.

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
@github-actions

github-actions Bot commented Apr 11, 2026

Copy link
Copy Markdown
Contributor

✅ CI Errors Resolved

All previously reported errors have been fixed. All builds passing.

Last checked: 2026-04-11T10:07:51Z

claude added 3 commits April 11, 2026 09:37
Three Phase L tests were failing on the windows-vs2022 (Release) CI job:
  - BVH_FrustumQuery_CullsBehindCamera
  - BVH_FrustumQuery_CullsBeyondFarPlane
  - BVH_Build_HandlesFiftyPrimitives

Two root causes, both my fault when authoring the tests:

1. The cull tests assumed BVHAccelerator::FrustumQuery does per-PRIMITIVE
   culling, but it only does per-LEAF culling. When two primitives share
   a leaf (default maxLeafSize=4), the leaf's bounding box covers both
   and the frustum test sees Intersecting → ALL primitives in the leaf
   are returned. My tests put an in-front primitive AND a behind-camera /
   past-far-plane primitive in the same BVH, expecting only the in-front
   one to come back. On Windows (and conceptually on any platform doing
   the math correctly) both come back because they share a single leaf.
   The Linux DirectXMath stub apparently produces a slightly different
   frustum that happened to mask this on the linux-gcc-release build.

   Fix: split each cull test into a SINGLE-primitive case so the BVH
   builds a leaf with bounds entirely outside the frustum. The new
   BVH_FrustumQuery_KeepsInFrontPrimitive test covers the positive
   side using the same single-primitive pattern.

2. BVH_Build_HandlesFiftyPrimitives put 50 primitives in a 10x5 grid
   with x ∈ [-4..5]. The right-edge primitive at x=5 has bounds
   [4.5, 5.5] in x. The frustum right plane sits at ≈ 4.143 (camera at
   z=-10, 45° vertical FOV, distance 10 from origin). On Windows MSVC
   Release the math correctly culls the rightmost primitives. The Linux
   stub apparently produces a slightly more permissive frustum and lets
   them through.

   Fix: rescale the grid so all primitives sit comfortably inside the
   ±4.143 frustum extent. New layout: 10x5 grid centred on the origin
   with 0.5-step spacing and 0.2 half-extent — max primitive bounds at
   ±2.45 in x and ±1.2 in y, well inside on every platform.

Adds a new comment block at the top of the cull-tests section explaining
the per-leaf vs per-primitive distinction so future test authors don't
make the same mistake.

Linux suite still 4611 / 0 / 0 (BVH tests are #ifdef SPARK_PLATFORM_WINDOWS
gated, so this commit doesn't change the Linux test count). Windows CI
should now pick up 11 BVH tests (one more than before because the cull
test was split into Cull + Keep) and pass cleanly.

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
Coverage is failing with "geninfo: ERROR: no .gcda files found in
build" on commits Phase K+ (I→T orphan activation branch). Earlier
runs on Phase I / J succeeded. The failure mode is deterministic (same
error on 08:36 and 09:38 runs, same 16-minute duration) which rules
out a stale cache as the root cause.

Without direct job log access, I need more visibility into what
SparkTests actually does in the coverage build. This commit adds four
diagnostics to the Test step, right after the SparkTests invocation:

  1. The PIPESTATUS[0] exit code (captures the actual SparkTests
     return code, not the tee return code after the || true).
  2. The last 80 lines of test-output.log (vs the current 5).
  3. .gcno file count (shows whether instrumentation was applied).
  4. .gcda file count + first 5 paths (shows whether gcov actually
     wrote counter data).

These four data points will tell me whether:
  - SparkTests crashed at startup (no .gcda, small .gcno count may
    or may not exist).
  - SparkTests ran but gcov failed to flush (no .gcda, normal .gcno).
  - The build cache is corrupted (0 .gcno files despite --coverage
    flags).
  - A test is crashing mid-run and InstallCrashHandlers's _exit(128
    + sig) is bypassing gcov's atexit flush.

The diagnostics are purely informational — they don't change the
pass/fail behaviour of the coverage step. If the next CI run passes,
the output tells me the root cause; if it fails again, same info +
the existing lcov error.

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
Phase L's MeshOptimizer_OptimizeVertexFetch_PreservesTriangleMeaning
test had an unused, out-of-bounds std::vector lookup that silently
read past the end of the `original` vector on Release builds but
aborted with SIGABRT on Debug builds with _GLIBCXX_ASSERTIONS (the
coverage job's default). The abort happened after the crash handler
installed itself, so InstallCrashHandlers's _exit(128 + sig) bypassed
gcov's atexit handler and no .gcda files were flushed — which is why
the coverage step failed with "geninfo: ERROR: no .gcda files found
in build" on every run since Phase L landed.

The buggy line was:

  const Vertex& origV = original[1 + ((i + 2) % 3) - (i == 0 ? 0 : 0)];

For i=0 the index is 1 + 2 - 0 = 3, but `original` only has 3 elements
(indices 0..2). The value was never used (the line ended with
`(void)origV;` to suppress the unused-variable warning), so the UB
was pure dead code that happened to trigger libstdc++'s hardened
operator[] bounds check and abort the entire test binary.

Fix: delete the dead origV lookup. The remaining assertion in the
loop is `EXPECT_TRUE(optV.x >= 0.0f || optV.y >= 0.0f || optV.z >=
0.0f)` which is the actual check the test was written to make.

Also reverts the diagnostic workflow patch from 11c51cb — the
four diagnostic prints (SparkTests exit status, test-output.log
tail, .gcno count, .gcda count, first .gcda paths) did their job
and identified the crashing test via the `[ CRASH  ]` stack trace,
so they can go back to the normal tail -5 output.

Full Linux suite remains clean: 4609 passed, 0 failed, 2 warned
(pre-existing known-flaky), 120439 assertions on linux-gcc-release.
The fixed test also builds cleanly under -D_GLIBCXX_ASSERTIONS
(standalone smoke compile).

https://claude.ai/code/session_01QoefgpfnywL2WtN99Eivrm
@github-actions

Copy link
Copy Markdown
Contributor

Code Coverage (GCC + lcov)

Utils/MemoryMonitor.h                          |85.7%    14| 0.0%  12|    -    0
Utils/MultiISA.h                               |42.9%    14| 0.0%   6|    -    0
Utils/NetworkHealthMonitor.cpp                 | 113%    15| 0.0%   2|    -    0
Utils/NetworkHealthMonitor.h                   |    -     0|    -   0|    -    0
Utils/OpaqueHandle.h                           | 282%    11| 0.0%  15|    -    0
Utils/ProcessLinux.cpp                         |16.5%   182| 0.0%  28|    -    0
Utils/Profiler.cpp                             |14.2%   113| 0.0%  15|    -    0
Utils/Profiler.h                               |36.4%    33| 0.0%  12|    -    0
Utils/RandomEngine.h                           |29.3%    41| 0.0%  12|    -    0
Utils/Result.h                                 | 100%    29| 0.0%  28|    -    0
Utils/RingBuffer.h                             | 108%    59| 0.0%  64|    -    0
Utils/ScopeGuard.h                             | 142%    36| 0.0%  51|    -    0
Utils/ScopedTimer.h                            |25.0%    12| 0.0%   3|    -    0
Utils/Serializer.h                             | 100%    48| 0.0%  42|    -    0
Utils/SparkConsole.cpp                         |28.5%   144| 0.0%  17|    -    0
Utils/SparkConsole.h                           | 100%     2| 0.0%   2|    -    0
Utils/SparkError.h                             |10.9%    55| 0.0%   6|    -    0
Utils/SplinePath.h                             |    -     0|    -   0|    -    0
Utils/StackTrace.h                             |10.8%    74| 0.0%   8|    -    0
Utils/StateMachine.h                           |54.0%    63| 0.0%  32|    -    0
Utils/StringUtils.h                            |18.1%   116| 0.0%  21|    -    0
Utils/Telemetry.h                              |20.7%   135| 0.0%  22|    -    0
Utils/ThreadDebugger.h                         |11.6%   199| 0.0%  23|    -    0
Utils/ThreadSafeQueue.h                        |27.5%    40| 0.0%  11|    -    0
Utils/TimerManager.h                           |19.8%    96| 0.0%  19|    -    0
Utils/UUID.h                                   |43.2%    37| 0.0%  16|    -    0
Utils/Validate.h                               |    -     0|    -   0|    -    0

[/home/runner/work/SparkEngine/SparkEngine/SparkSDK/Include/Spark/]
IEngineContext.h                               |7300%     1| 0.0%   1|    -    0
ServiceInterfaces.h                            | 200%     3| 0.0%   3|    -    0
Version.h                                      |    -     0|    -   0|    -    0
================================================================================
                                         Total:|28.1% 27318| 0.0%  4k|    -    0

Per-Subsystem Coverage

Subsystem Lines Hit Coverage Threshold Status
AI 2817 734 26.1% 35%
Animation 160 154 96.2% 35%
Audio 0 0 0% 30%
Camera 0 0 0% 40%
Core 2310 1449 62.7% 40%
ECS 190 115 60.5% 40%
Editor 7377 2823 38.3% 25%
GameModules 6244 3130 50.1% 30%
Graphics 10745 6178 57.5% 30%
Networking 3420 2269 66.3% 35%
Physics 0 0 0% 35%
Scripting 0 0 0% 30%
Utils 7688 4864 63.3% 60%

Total: 53% (21716/40951 lines)

@Krilliac
Krilliac merged commit 5f57747 into Working Apr 11, 2026
44 checks passed
@Krilliac
Krilliac deleted the claude/engine-roadmap-8Kc2c branch April 11, 2026 11:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants