Gaussian Renderer Refactor Memory¶
Owner role: Rendering architecture lead / refactor orchestrator
Branch context: /mnt/c/projects/godotgs-clean-refactor (refactor/gs-renderer-architecture, dirty worktree)
Purpose¶
This document is the implementation memory for the staged Gaussian Splatting renderer refactor. It records what we validated in code, what we generated, why the sequence is structured this way, and what must remain stable while migrating.
This is not a rewrite plan. It is a migration plan that preserves shipping behavior and keeps GaussianSplatRenderer as the public facade.
Reality Check Performed¶
- Regenerated architecture artifacts from current branch code using:
python3 scripts/generate_architecture_diagrams.py- Confirmed generated outputs under
docs/architecture/generated: README.mdsubsystem-dependencies.mdrenderer-coupling.mdrenderer-direct-access.mdcoupling-report.mdlocal-dependencies.csvsummary.json- Latest generated metrics:
source_files: 272include_edges: 836symbol_reference_edges: 1685- Parallel investigation was delegated to agents:
- Agent Carver: full state/config consumer classification and mutability risk map.
- Agent Ptolemy: sorting seam + composition-root coupling analysis and sequence.
Findings (Ordered By Risk)¶
- Mutable-from-const provider contract is a primary blocker and must be explicitly addressed early.
IFrameStateProviderreturns mutable references fromconstmethods ingaussian_splat_renderer.h.- Key locations:
modules/gaussian_splatting/renderer/gaussian_splat_renderer.h:332-340. - Fallback provider path returns mutable static fallback objects in
gaussian_splat_renderer.cpp. - Key locations:
modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp:467-527. -
Impact: impossible to enforce snapshot-only read paths while mutable escape hatches remain exposed through
constinterfaces. -
State/config coupling is broad and concentrated in renderer-centric hot paths, not only in orchestrator count.
- Generated direct-access hotspots confirm this:
render_diagnostics_orchestrator.cpp,render_sorting_orchestrator.cpp,render_resource_orchestrator.cpp,performance_monitors.cpp. - Evidence:
docs/architecture/generated/coupling-report.mdandsummary.json. -
Impact: renaming or moving orchestrators without reducing mutable access paths will not materially improve architecture.
-
Observability consumers are mixed; treating the whole bucket as read-only snapshot migration would fail.
- Clean snapshot candidate:
core/performance_monitors.cpp(read-mostly pull model). - Mixed mutator consumers:
interfaces/debug_overlay_system.cpp:183-287mutates renderer debug config/state.interfaces/painterly_renderer.cpp:1549-1562pulls broad mutable renderer state on production path.
-
Impact: split phase required (
1asnapshots for query consumers,1bexplicit mutator APIs for mixed consumers). -
Sorting seam still leaks renderer ownership below orchestrator layer.
- Renderer-dependent APIs still present in pipeline header:
modules/gaussian_splatting/interfaces/gpu_sorting_pipeline.h:64-65modules/gaussian_splatting/interfaces/gpu_sorting_pipeline.h:86modules/gaussian_splatting/interfaces/gpu_sorting_pipeline.h:237
- Implementation still reaches through renderer state in:
modules/gaussian_splatting/interfaces/gpu_sorting_pipeline.cpp:2007+modules/gaussian_splatting/interfaces/gpu_sorting_pipeline.cpp:2757+
-
Impact: sorting is not decoupled enough to be a stable service seam.
-
Composition root has real callback/pointer mesh complexity and renderer anchoring.
- Constructor wiring is dense and renderer-pointer based:
modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp:554-704.
- Orchestrator headers store renderer pointers directly:
modules/gaussian_splatting/renderer/render_streaming_orchestrator.h:13,38modules/gaussian_splatting/renderer/render_sorting_orchestrator.h:21,71
-
Impact: composition-root cleanup is justified, but only if it removes dependency direction issues (not just constructor reshuffling).
-
Tests currently rely on mutating internals directly.
- Examples:
modules/gaussian_splatting/tests/test_renderer_pipeline.h:537-538modules/gaussian_splatting/tests/test_renderer_pipeline.h:638modules/gaussian_splatting/tests/test_renderer_pipeline.h:1856
- Impact: tightening mutable access without replacement test hooks will break compatibility surfaces.
Renderer State/Config Consumer Map¶
Category A: Read-only diagnostics/monitoring (snapshot-first)¶
modules/gaussian_splatting/core/performance_monitors.cpp(high call volume, mostly query usage)- Read-mostly node/director integration:
modules/gaussian_splatting/nodes/gaussian_splat_world_3d.cppmodules/gaussian_splatting/nodes/gaussian_splat_node_helpers.cppmodules/gaussian_splatting/core/gaussian_splat_scene_director.cpp
Category B: Read-write production path (mutator-first)¶
modules/gaussian_splatting/renderer/render_pipeline_stages.cppmodules/gaussian_splatting/renderer/render_sorting_orchestrator.cppmodules/gaussian_splatting/renderer/render_resource_orchestrator.cppmodules/gaussian_splatting/renderer/render_data_orchestrator.cppmodules/gaussian_splatting/renderer/render_streaming_orchestrator.cppmodules/gaussian_splatting/renderer/render_output_orchestrator.cppmodules/gaussian_splatting/renderer/render_instancing_orchestrator.cppmodules/gaussian_splatting/interfaces/painterly_renderer.cppmodules/gaussian_splatting/interfaces/gpu_sorting_pipeline.cpp
Category C: Test-only¶
modules/gaussian_splatting/tests/test_renderer_pipeline.hmodules/gaussian_splatting/tests/test_gaussian_splat_node.cpp
Category D: Editor/tooling and mixed diagnostics¶
modules/gaussian_splatting/interfaces/debug_overlay_system.cppmodules/gaussian_splatting/renderer/render_debug_state_orchestrator.cppmodules/gaussian_splatting/interfaces/interactive_state_manager.cppmodules/gaussian_splatting/renderer/render_diagnostics_orchestrator.cpp(mixed: query + mutation side effects)
Snapshot-first candidates¶
performance_monitors.cpp- read-only stats export surfaces in nodes/director paths
- query-only subsets of diagnostics once const-escape is removed
Mutator-first candidates¶
- debug overlay mutators (
set_renderer_overlay_opacity, invalidation/rebuild paths) - painterly population path
- sorting/streaming/data orchestrators and pipeline stages
Phase 1a Execution Log (Completed)¶
Scope guardrails¶
- Query/read paths only.
- No debug overlay redesign.
- No painterly mutation redesign.
- No sorting API cleanup.
- Rollback remains limited to:
modules/gaussian_splatting/renderer/gaussian_splat_renderer.hmodules/gaussian_splatting/renderer/render_diagnostics_orchestrator.cppmodules/gaussian_splatting/core/performance_monitors.cpp
Slice 1 (Completed): streaming/LOD monitor snapshot seam¶
- Date: 2026-03-23
- Introduced:
GaussianSplatRenderer::MonitorStreamingSnapshotGaussianSplatRenderer::get_monitor_streaming_snapshot() const- Migrated monitor families:
- VRAM budget monitors
- streaming core monitors
- LOD monitors
- memory-stream monitors
- chunk-capacity + advanced LOD analytics
- SH-compression monitors
- Verification:
- Windows build + module lane passed (external verification run).
Slice 2 (Completed): query-only completion for timing/route/projection fallback reads¶
- Date: 2026-03-23
- Added read-only snapshot fields for monitor fallbacks:
- route/sort route identifiers
- stage timing fields used by GPU timing monitors
- performance/frame counters used by projection monitors
- Replaced remaining direct timing/route/projection monitor reads with snapshot reads.
- Verification:
python3 tests/ci/run_module_tests.py --guard-onlypassed locally.
Slice 3 (Completed): cache-contract hardening without redesign¶
- Date: 2026-03-23
- Hardening changes:
- monitor snapshot cache state is now
thread_local(eliminates shared cross-thread mutable cache state), - cache key expanded from
(renderer, frame_counter)to a compact monitor-focused key (frame + route ids + stage timing signals + key perf counters), _get_visible_splat_count()fallback now uses snapshot (removes remaining projection fallback seam leak).- Verification:
python3 tests/ci/run_module_tests.py --guard-onlypassed locally.
Residual risks carried to Phase 1a closeout¶
- Low: cache key is intentionally partial, so some non-timing fields can still be stale within the same frame if updated after the first monitor read.
- This is accepted for minimal Slice 3 scope and must be documented as a cache contract.
- Low: route invalidation keying uses hashed strings (
route_uid/sort_route_uid), so collision risk is non-zero but negligible in practice.
Phase 1a closeout evidence¶
- Native Windows verification (post Slice 3 and const accessor fix):
- Build:
scons platform=windows target=editor dev_build=yes tests=yes module_gaussian_splatting_enabled=yes -j%NUMBER_OF_PROCESSORS%passed. - Guard lane: passed.
- Module lane: passed (
GaussianSplatting144 tests / 4,066 assertions). - GPU-dependent lanes stayed advisory in headless/no-GPU context.
- Architecture pack regenerated after Phase 1a implementation:
python3 scripts/generate_architecture_diagrams.py- Updated summary:
source_files=272,include_edges=836,symbol_reference_edges=1685. - Notable seam signal:
core/performance_monitors.cppdropped from renderer state-access hotspot 101 to 3.
Phase 1b Prep Map (Planning Only, No Code Changes)¶
Exact inventory: mutable-from-const provider contracts to remove¶
IFrameStateProvidercurrently exposes mutable state fromconstmethods:SortingState &get_sorting_state() constRenderConfig &get_render_config() constJacobianDebugConfig &get_jacobian_debug() constResourceState &get_resource_state() constFrameState &get_frame_state() constPerformanceState &get_performance_state() constSubsystemState &get_subsystem_state() const- Location:
modules/gaussian_splatting/renderer/gaussian_splat_renderer.h:334-340 FrameStateProviderreturns mutable static fallback objects for the same methods whenrenderer == nullptr:- Locations:
modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp:467-528 RenderFrameContext::FrameDepsstores mutable pointers for frame/state buckets while the provider is passed around asconst IFrameStateProvider *:- Location:
modules/gaussian_splatting/renderer/gaussian_splat_renderer.h:275-297 - Stage/context structs carry
const IFrameStateProvider *while calling mutating state methods through it: - Locations:
gaussian_splat_renderer.h:272,377,385,436,448
Full callsite migration map (grouped)¶
Query-only consumers¶
modules/gaussian_splatting/core/performance_monitors.cpp- Status: already migrated to snapshot seam in Phase 1a.
- Remaining direct state reads are cache-key inputs only (
get_frame_state(),get_debug_state(),get_performance_state()), not monitor payload read paths. modules/gaussian_splatting/renderer/render_pipeline_stages.cpp- Query-only provider callsites that should move to read-only view contracts:
- sort/index resource lookup: line
195 - culler availability checks: line
444 - render device / pipeline feature / frame plan reads: lines
869,1092,1540,1788,1841,2034,2174,2227 - render config signature reads: line
1272
- sort/index resource lookup: line
Mutating production consumers¶
modules/gaussian_splatting/renderer/render_pipeline_stages.cpp- State mutation through provider-returned mutable refs:
- frame/sort count writes and skip resets: lines
725-743,1462-1490 - raster/composite metrics writes: lines
1957,1981,2005,2013,2020-2032,2104-2106,2221-2232,2248,2265,2315,2342 - resource/compositor cache mutation via provider-derived state: lines
1971-1972,2042-2046,2212-2217
- frame/sort count writes and skip resets: lines
modules/gaussian_splatting/renderer/render_instancing_orchestrator.cpp- Provider used as mutable execution context for cull/sort stage orchestration:
- lines
155-186
- lines
modules/gaussian_splatting/interfaces/painterly_renderer.cpp- Direct
GaussianSplatRenderer *facade consumer, not anIFrameStateProviderconsumer. - Broad mutable facade reach-through on production path:
- state/config bundle capture at
1549-1562 - mutation-heavy painterly/raster integration and debug/perf updates:
1843-1991
- state/config bundle capture at
Tooling/debug consumers¶
modules/gaussian_splatting/interfaces/debug_overlay_system.cpp- Direct
GaussianSplatRenderer *facade consumer, not anIFrameStateProviderconsumer. - Explicit mutators:
set_renderer_overlay_opacity:183-197invalidate_renderer_overlay:199-218invalidate_renderer_hud:220-235rebuild_renderer_overlay_statistics_from_cache:237-275rebuild_renderer_performance_hud_lines:277-430
modules/gaussian_splatting/interfaces/debug_overlay_macros.h- Macros generate renderer-state mutating setters:
GS_DEBUG_OVERLAY_RENDERER_SETTER_OVERLAY_IMPL:63-76GS_DEBUG_OVERLAY_RENDERER_SETTER_HUD_IMPL:82-95
Test-only consumers¶
modules/gaussian_splatting/tests/test_renderer_pipeline.h- Direct internal mutation:
- streaming system tear-down via mutable state:
537-538,638 - compositor cache internals mutation:
1856-1859
- streaming system tear-down via mutable state:
- Read-only but internal-state-dependent assertions:
- streaming state checks:
554,652,776 - subsystem output compositor access:
1701,1832
- streaming state checks:
modules/gaussian_splatting/tests/test_gaussian_splat_node.cpp- read-only scene state assertions:
746-758
Proposed replacement seams by group¶
Query-only consumers¶
- Introduce
IFrameStateView(const-only) for stage/query paths. - Move query-only stage helpers and signatures to
const IFrameStateView &. - Keep monitor read paths on snapshot seam; no direct mutable state exposure.
JacobianDebugConfigstarts inIFrameStateViewby default unless a concrete production-path mutator is identified during migration.
Mutating production consumers¶
- Introduce
IFrameMutationAccessfor production writes, separate from read-only view. IFrameMutationAccessowns only currently-required mutable buckets:FrameState,PerformanceState,ResourceState,SortingState, and explicit subsystem mutator access where needed.- Stage inputs that mutate become
IFrameMutationAccess *; pure query stages remain onIFrameStateView *. - Treat painterly as an explicit
1b.2hotspot sub-slice because it currently pulls a very wide renderer facade surface in one path.
Tooling/debug consumers¶
- Split overlay into command/query seams:
DebugOverlayQueryView(read-only metrics and snapshots)DebugOverlayCommandSink(invalidate HUD/overlay, set flags/opacity)- Keep renderer facade stable by delegating current public methods to these seams.
- Note: this is a direct-facade migration, not a provider-interface migration.
Test-only consumers¶
- Replace direct mutable internals with narrow test hooks on renderer/output compositor seams:
test_set_streaming_system_for_test(Ref<GaussianStreamingSystem>)test_clear_streaming_system_for_test()test_get_output_cache_snapshot() consttest_override_output_cache_for_test(const OutputCacheOverride &)- Optional friend test harness only for unavoidable edge cases.
Phase 1b execution order and rollback points¶
- 1b.0 Provider split scaffold (no callsite migration yet)
- Add
IFrameStateView+IFrameMutationAccess. - Keep adapters so existing callsites compile unchanged.
- Rollback point RP-1: remove new interfaces/adapters only.
- 1b.1 Query-only callsite migration
- Move query-only stage helpers to
IFrameStateView. - Prove no behavior change with guard/module lanes.
- Acceptance caveat: state-bucket mutation via provider is blocked for migrated query paths, but service-pointer mutation risk remains until service seams are narrowed.
- Rollback point RP-2: revert query-only signature/callsite set.
- 1b.2 Mutating production migration
- Move mutating stage/provider paths to
IFrameMutationAccess. - Split execution into:
1b.2aprovider-based production writers (render_pipeline_stages,render_instancing_orchestrator)1b.2bpainterly direct-facade migration
- Remove mutable-from-const methods from
IFrameStateProvideradapters once all mutating production callsites are migrated. - Rollback point RP-3: re-enable adapter bridge methods temporarily.
- 1b.3 Tooling/debug mixed-consumer migration
- Introduce explicit debug command/query seams and migrate direct-facade
debug_overlay_systemcallsites. - Keep behavior and HUD/overlay output stable.
- Rollback point RP-4: keep new seams, restore old delegations.
- 1b.4 Test-hook migration before lock-down
- Replace direct test internals mutation with test hooks.
- Rollback point RP-5: temporarily keep compatibility shim methods under test-only naming.
- 1b.5 Lockdown prep completion criteria
- No mutable-from-const provider methods remain.
- Query-only consumers do not require mutable renderer state access.
- Debug/painterly/test paths have replacement seams/hooks in place.
Phase 1b.0 implementation status (scaffold-only, behavior-preserving)¶
- Date: 2026-03-23
- Scope applied:
- Added
IFrameStateViewandIFrameMutationAccessinmodules/gaussian_splatting/renderer/gaussian_splat_renderer.h. - Kept existing
IFrameStateProvidercallsite surface intact as a legacy compatibility layer. - Added adapter bridge methods on
IFrameStateProvider:- view side:
get_*_view()methods forward to legacy getters, - mutation side:
get_*_mut()methods forward to legacy getters.
- view side:
- Explicitly preserved for this slice:
- No callsite signature migrations (
render_pipeline_stages, orchestrators, tooling, painterly, tests unchanged). - No behavior changes in render path execution.
JacobianDebugConfigremains classified as view-first (get_jacobian_debug_view()), not added to mutation access.- Caveat carried forward:
IFrameStateViewis currently const-only for state buckets, but still exposes mutable service pointers (OutputCompositor *,GPUCuller *,PainterlyRenderer *,GPUSortingPipeline *,RenderingDevice *).- Therefore, Phase
1b.1does not yet provide full compile-time mutation prevention through service dependencies; this must be tightened in subsequent narrowing slices. - Rollback boundary:
- Revert only the interface scaffold/bridge hunk in
gaussian_splat_renderer.h(RP-1). - Verification status:
git diff --checkpassed for scaffold edits.- Full native Windows build/test rerun passed on the branch in subsequent validation workflows:
- Build: pass.
- Guard lane: pass.
- Module lane: pass.
Phase 1b.1 implementation status (query-only callsite migration, slice 1)¶
- Date: 2026-03-23
- Scope applied:
- Query-only helper signatures moved from
IFrameStateProvidertoIFrameStateViewinmodules/gaussian_splatting/renderer/render_pipeline_stages.cpp:_get_sort_indices_buffer(...)_compute_cull_config_signature(...)
- Query-only config/debug reads moved to view getters:
get_render_config_view()for color-grading signature pathget_render_config_view()andget_jacobian_debug_view()inside tile fallback setup
- Explicitly preserved for this slice:
- No service-pointer narrowing.
- No debug overlay migration.
- No painterly migration.
- No sorting-seam API work.
- No mutating-stage provider signature changes.
- Rollback boundary:
- Revert only the query-only signature/callsite edits in
render_pipeline_stages.cpp(RP-2). - Verification status:
git diff --checkpassed for the slice.- Local phase checks passed via
python3 scripts/refactor_phase_runner.py local-checks --phase 1b.2b --no-regen-architecture. - Native Windows verification passed via
Gaussian Production Gatesonrefactor/gs-renderer-architecture:- Build: pass (Windows self-hosted module-validation lane).
- Guard lane: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions). - Runtime/benchmark gates: pass (runtime harness, world-streaming gate, large-scene benchmark, eviction-churn benchmark).
- Native Windows verification passed:
- Build: pass (incremental,
render_pipeline_stages.cpprecompiled). - Guard lane: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions).
- Build: pass (incremental,
Phase 1b.1 implementation status (query-only callsite migration, slice 3)¶
- Date: 2026-03-23
- Scope applied:
- Additional query-only provider reads were migrated to
IFrameStateViewaliases in:modules/gaussian_splatting/renderer/render_pipeline_stages.cppmodules/gaussian_splatting/renderer/render_instancing_orchestrator.cppmodules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp
- In
render_pipeline_stages.cpp, query-fetch usage now routes throughstate_viewin:SortStage::execute(...)RasterCompositeStage::execute(...)RasterStage::resolve_painterly_output(...)RasterStage::render_baseline_stage(...)CompositeStage::execute(...)render_sorted_splats_with_context(...)
build_frame_plan(...)callsites now source scene/streaming/sorting/resource/subsystem/pipeline-feature inputs viaframe_providerview accessors instead of broad direct renderer getters.- Snapshot initialization in
render_sorted_splats(...)now readsFrameStateandSortingStatevia view getters (get_frame_state_view(),get_sorting_state_view()). - Explicitly preserved for this slice:
- No service-pointer narrowing.
- No debug overlay migration.
- No painterly direct-facade redesign.
- No sorting-seam API work.
- No mutating-stage provider signature changes.
- Rollback boundary:
- Revert only slice-3 query-only alias/read edits in:
render_pipeline_stages.cpprender_instancing_orchestrator.cppgaussian_splat_renderer.cpp
- Verification status:
git diff --checkpassed for the slice.- Native Windows verification passed:
- Build: pass (incremental, touched renderer files rebuilt).
- Guard lane: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions).
Phase 1b.1 implementation status (query-only callsite migration, slice 4)¶
- Date: 2026-03-23
- Scope applied:
- Remaining query-only provider reads in
RasterStage::render_tile_fallback(...)were routed throughIFrameStateView:get_frame_plan()get_pipeline_features()FrameState::frame_counterread used for wind-time calculation
- Location:
modules/gaussian_splatting/renderer/render_pipeline_stages.cpp - Explicitly preserved for this slice:
- No service-pointer narrowing.
- No debug overlay migration.
- No painterly direct-facade redesign.
- No sorting-seam API work.
- No mutating-stage provider signature changes.
- Rollback boundary:
- Revert only slice-4 query-only read edits in
render_pipeline_stages.cpp(RP-2). - Verification status:
git diff --checkpassed for the slice.- Native Windows verification passed (build + guard-only + module lane):
- Build: pass (incremental, 3 files recompiled).
- Guard lane: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions).
Phase 1b.1 implementation status (query-only callsite migration, slice 5)¶
- Date: 2026-03-23
- Scope applied:
- Additional query-fetch service reads in
modules/gaussian_splatting/renderer/render_pipeline_stages.cppnow route through existingIFrameStateViewaliases:CullStage::execute(...):get_gpu_culler(),get_rendering_device()SortStage::execute(...):get_gpu_culler(),get_sorting_pipeline(),get_rendering_device()RasterStage::render_tile_fallback(...):get_rendering_device()RasterStage::try_reuse_cached_render(...):get_output_compositor()RasterStage::render_baseline_stage(...):get_output_compositor()RasterStage::render_painterly_or_baseline_stage(...):get_painterly_renderer()render_sorted_splats_with_context(...):get_output_compositor()
- Explicitly preserved for this slice:
- No service-pointer narrowing.
- No debug overlay migration.
- No painterly direct-facade redesign.
- No sorting-seam API work.
- No mutating-stage provider signature changes.
- Rollback boundary:
- Revert only slice-5 query-fetch alias/read edits in
render_pipeline_stages.cpp(RP-2). - Verification status:
- Implementation status: present in branch (not superseded).
- Review status: approved in-thread (service-pointer caveat acknowledged).
git diff --checkpassed for the slice.- Native Windows build + module lane status not yet re-asserted in this thread (treat as pending until explicitly confirmed).
Phase 1b.1 implementation status (query-only callsite migration, slice 6)¶
- Date: 2026-03-23
- Scope applied:
- Query-only provider fetch in frame-entry skip handling now routes through
IFrameStateView:execute_frame_entry(...):get_gpu_culler()
- Location:
modules/gaussian_splatting/renderer/render_pipeline_stages.cpp - No behavior/path changes were introduced; this slice also normalized indentation in already-touched
render_pipeline_stages.cppblocks to keep the migration diff reviewable. - Explicitly preserved for this slice:
- No service-pointer narrowing.
- No debug overlay migration.
- No painterly direct-facade redesign.
- No sorting-seam API work.
- No mutating-stage provider signature changes.
- Rollback boundary:
- Revert only slice-6 query-only alias/read edit and local formatting cleanup in
render_pipeline_stages.cpp(RP-2). - Verification status:
- Implementation status: present in branch (not superseded).
- Review status: approved in-thread (service-pointer caveat acknowledged).
git diff --checkpassed for the slice.- Native Windows build + module lane status not yet re-asserted in this thread (treat as pending until explicitly confirmed).
Phase 1b.1 implementation status (query-only callsite migration, slice 7)¶
- Date: 2026-03-23
- Scope applied:
- Additional query-only reads in
modules/gaussian_splatting/renderer/render_instancing_orchestrator.cppnow route throughIFrameStateView:- Readiness precheck: streaming-state read (
get_streaming_state()) now sourced from a localFrameStateProviderview alias. - Instanced render loop: frame-state reads for
before_frame_counter,render_time_ms, andvisible_splat_countnow source fromframe_state_view.get_frame_state_view().
- Readiness precheck: streaming-state read (
- Local indentation cleanup was applied in the touched loop block for reviewability; no API or behavior-path changes were introduced.
- Explicitly preserved for this slice:
- No service-pointer narrowing.
- No debug overlay migration.
- No painterly direct-facade redesign.
- No sorting-seam API work.
- No mutating-stage provider signature changes.
- Rollback boundary:
- Revert only slice-7 query-only read edits and local formatting cleanup in
render_instancing_orchestrator.cpp. - Verification status:
git diff --checkpassed for the slice.- Native Windows verification passed (build + guard-only + module lane), per reported external runner result on 2026-03-23.
Phase 1b.1 implementation status (query-fetch migration under service-pointer caveat, slice 8)¶
- Date: 2026-03-23
- Scope applied:
modules/gaussian_splatting/renderer/render_pipeline_stages.cpp(RasterStage::render_tile_fallback(...)):- Streaming-state fallback read for
total_gaussiansnow sources fromstate_view.get_streaming_state()instead of direct renderer getter. - Debug-overlay projection-log gate now reads from
state_view.get_subsystem_state_view().debug_overlay_systeminstead of direct renderer getter.
- Streaming-state fallback read for
- The function still mutates service-owned state/render flow later; this slice is explicitly query-fetch migration under the known
IFrameStateViewservice-pointer caveat, not immutable query isolation. - Explicitly preserved for this slice:
- No service-pointer narrowing.
- No debug overlay redesign.
- No painterly direct-facade redesign.
- No sorting-seam API work.
- No mutating-stage provider signature changes.
- Rollback boundary:
- Revert only slice-8 query-read substitutions in
render_pipeline_stages.cpp. - Verification status:
git diff --checkpassed for the slice.- Native Windows verification passed (build + guard-only + module lane):
- Build: pass (incremental,
render_pipeline_stages.cpponly). - Guard lane: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions).
- Build: pass (incremental,
Phase 1b.1 implementation status (query-only callsite migration, slice 9)¶
- Date: 2026-03-23
- Scope applied:
modules/gaussian_splatting/renderer/render_pipeline_stages.cpp:- Pipeline trace/frame-event frame-counter reads now source from
IFrameStateViewvia localFrameStateProvideraliases (_begin_pipeline_trace(...),_record_pipeline_event(...)). prepare_render_frame_context(...)frame-id assignment now sources fromstate_view.get_frame_state_view().frame_counter.log_stage_result(...)60-frame log cadence check now sources fromIFrameStateViewframe-state read.
- Pipeline trace/frame-event frame-counter reads now source from
- This slice is read-only query migration; no service-pointer fetch or mutator signature changes were introduced.
- Explicitly preserved for this slice:
- No service-pointer narrowing.
- No debug overlay or painterly redesign.
- No sorting-seam API work.
- No mutating-stage provider signature changes.
- Rollback boundary:
- Revert only slice-9 frame-counter query-read substitutions in
render_pipeline_stages.cpp. - Verification status:
git diff --checkpassed for the slice.- Native Windows verification covered by the subsequent slice-10 lane (same touched file state):
- Build: pass (incremental,
render_pipeline_stages.cpponly). - Guard lane: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions).
- Build: pass (incremental,
Phase 1b.1 implementation status (query-only callsite migration, slice 10)¶
- Date: 2026-03-23
- Scope applied:
modules/gaussian_splatting/renderer/render_pipeline_stages.cpp(execute_frame_entry(...)pre-plan state selection):- Added a local pre-plan
FrameStateProvider+IFrameStateViewalias for read-side fallback sourcing before final provider wiring. - Fallback reads for
SceneState,StreamingState, andPipelineFeatureSetnow route throughpreplan_viewinstead of direct renderer getters.
- Added a local pre-plan
- Mutating fallback references (
SortingState,ResourceState,SubsystemState) remain unchanged in this slice. - Explicitly preserved for this slice:
- No service-pointer narrowing.
- No debug overlay or painterly redesign.
- No sorting-seam API work.
- No mutating-stage provider signature changes.
- Rollback boundary:
- Revert only slice-10 pre-plan fallback query-read substitutions in
render_pipeline_stages.cpp. - Verification status:
git diff --checkpassed for the slice.- Native Windows verification passed (build + guard-only + module lane):
- Build: pass (incremental,
render_pipeline_stages.cpponly). - Guard lane: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions).
- Build: pass (incremental,
Phase 1b.1 implementation status (batched frame-context provider wiring + query-fetch migration under caveat, slice 11)¶
- Date: 2026-03-23
- Scope applied:
modules/gaussian_splatting/renderer/render_pipeline_stages.cpp:prepare_render_frame_context(...)dependency assembly now routes service fetches throughIFrameStateView(output_compositor,gpu_culler,painterly_renderer,sorting_pipeline,rendering_device,pipeline_features) instead of direct renderer getters.- Mutable state-bucket dep pointers in frame context (
sorting_state,render_config,jacobian_debug,resource_state,frame_state,performance_state,subsystem_state) now route throughFrameStateProvideraccessors instead of direct renderer getters. execute_frame_entry(...)pre-plan fallback for mutable buckets (sorting_state,resource_state,subsystem_state) now routes through the local pre-plan provider.
- This slice intentionally includes mutable-bucket wiring through the legacy provider contract; it is not immutable query isolation.
- Explicitly preserved for this slice:
- No service-pointer narrowing.
- No debug overlay or painterly redesign.
- No sorting-seam API work.
- No mutating-stage provider signature changes.
- Rollback boundary:
- Revert only slice-11 frame-context/pre-plan wiring substitutions in
render_pipeline_stages.cpp. - Verification status:
git diff --checkpassed for the slice.- Native Windows verification passed (build + guard-only + module lane):
- Build: pass (incremental,
render_pipeline_stages.cpponly). - Guard lane: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions).
- Build: pass (incremental,
Phase 1b.1 implementation status (batched instancing provider wiring + query-fetch migration under caveat, slice 12)¶
- Date: 2026-03-23
- Scope applied:
modules/gaussian_splatting/renderer/render_instancing_orchestrator.cpp(RenderInstancingOrchestrator::render_instanced(...)):- Added a root
FrameStateProviderand split aliases forIFrameMutationAccessandIFrameStateView. - Streaming readiness query now reads through
IFrameStateView(get_streaming_state()), replacing direct renderer state-bucket access. - Readiness-failure write path now updates
FrameState,SortingState, andPerformanceMetricsthrough provider mutation access instead of direct renderer getters. - Instanced frame-plan build now sources scene/streaming/sorting/resource/subsystem/pipeline-feature queries through
IFrameStateView. - Loop/frame aggregation reads (
frame_counter,render_time_ms,visible_splat_count) now route through view aliases; frame-counter rollback and final aggregate writes now route through root mutation access.
- Added a root
- This slice intentionally uses the legacy provider contract for mutable buckets and keeps direct facade calls where no provider seam exists (instance-pipeline buffers/debug state).
- Explicitly preserved for this slice:
- No service-pointer narrowing.
- No debug overlay or painterly redesign.
- No sorting-seam API work.
- No mutating-stage provider signature changes.
- Rollback boundary:
- Revert only slice-12 provider/view rewiring in
render_instancing_orchestrator.cpp. - Verification status:
git diff --checkpassed for touched files.- Local guard-only lane passed (
python3 tests/ci/run_module_tests.py --guard-only). - Native Windows verification passed (build + guard-only + module lane):
- Build: pass (incremental,
render_instancing_orchestrator.cpponly). - Guard lane: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions).
- Build: pass (incremental,
Phase 1b.1 implementation status (batched data-orchestrator provider wiring + query-fetch migration under caveat, slice 13)¶
- Date: 2026-03-23
- Scope applied:
modules/gaussian_splatting/renderer/render_data_orchestrator.cpp:- Added local
FrameStateProvideraliases in constructor and data/update paths (IFrameStateView+IFrameMutationAccess) and rewired state-bucket reads/writes away from direct renderer getters for: SubsystemStateaccess used by memory-stream device manager wiring and static-chunk culler state.PerformanceStatemetrics initialization/reset during data activation and failure fallback.SortingState/FrameStateresets in data clear and streaming initialization paths.ResourceStatebuffer-manager readiness and clear path in data upload prep.- Preserved direct renderer calls for non-provider surfaces (
DeviceState, performance settings, cull multiplier/slack).
- Added local
- This slice intentionally keeps legacy provider mutability semantics and does not claim immutable dependency isolation.
- Explicitly preserved for this slice:
- No service-pointer narrowing.
- No debug overlay or painterly redesign.
- No sorting-seam API work.
- No mutating-stage provider signature changes.
- Rollback boundary:
- Revert only slice-13 provider/view rewiring in
render_data_orchestrator.cpp. - Verification status:
git diff --checkpassed for touched files.- Local guard-only lane passed (
python3 tests/ci/run_module_tests.py --guard-only). - Native Windows verification passed (build + guard-only + module lane):
- Build: pass (incremental,
render_data_orchestrator.cpponly). - Guard lane: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions).
- Build: pass (incremental,
Phase 1b.1 implementation status (batched renderer-orchestrator provider/view rewiring under caveat, slice 14)¶
- Date: 2026-03-23
- Scope applied:
modules/gaussian_splatting/renderer/render_device_orchestrator.cpp:- Frame-id diagnostics now route through
FrameStateProviderview reads instead of directrenderer->get_frame_state()reads in device/submission/sync error paths. - Rasterizer output tracking now routes through
IFrameStateView::get_subsystem_state_view()instead of direct subsystem getter access.
- Frame-id diagnostics now route through
modules/gaussian_splatting/renderer/render_streaming_orchestrator.cpp:- Added local provider aliases in
ensure_instance_streaming_system(...),sync_instance_pipeline_assets(...),render_streaming_frame(...), andtick_streaming_only(...). - Rewired
SceneState,SubsystemState,PerformanceState,ResourceState, andFrameStateaccesses to provider view/mutation paths where available. - Kept direct facade reads for non-provider surfaces and known 1b.1 caveat surfaces (
StreamingStatemutation paths,DeviceState, performance settings, cull multiplier/slack, debug state).
- Added local provider aliases in
- This slice remains migration-under-caveat work; it does not claim immutable dependency isolation.
- Explicitly preserved for this slice:
- No service-pointer narrowing.
- No debug overlay or painterly redesign.
- No sorting-seam API work.
- No mutating-stage provider signature changes.
- Rollback boundary:
- Revert only slice-14 rewiring in
render_device_orchestrator.cppandrender_streaming_orchestrator.cpp. - Verification status:
git diff --checkpassed for touched files.- Local guard-only lane passed (
python3 tests/ci/run_module_tests.py --guard-only). - Native Windows verification passed via
Gaussian Production Gatesonrefactor/gs-renderer-architecture:- Build: pass (Windows self-hosted module-validation lane).
- Guard lane: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions).
Phase 1b.2a implementation status (stage-writer split with explicit mutation access, slice 15)¶
- Date: 2026-03-24
- Scope applied:
modules/gaussian_splatting/renderer/gaussian_splat_renderer.h:- Stage carriers were split so query-only stage inputs (
CullStageInput,SortStageInput) now carryconst IFrameStateView *. - Mutating raster-stage input now carries both
const IFrameStateView *andIFrameMutationAccess *. RenderFrameContextcontinues to carry the legacystate_providerbridge, but also exposes explicitstate_view/mutation_accessslots for in-flight stage execution.
- Stage carriers were split so query-only stage inputs (
modules/gaussian_splatting/renderer/render_pipeline_stages.h:reset_render_state_for_frame(...)now accepts explicitIFrameStateView+IFrameMutationAccessinstead of a const provider.
modules/gaussian_splatting/renderer/render_pipeline_stages.cpp:- Added
_resolve_state_view(...)and_resolve_mutation_access(...)helpers so older provider-only callers can bridge into the new split contract without behavior changes. execute_frame_entry(...)now resolves explicit view/mutation access before stage dispatch and uses mutation access for frame-count writes.RasterCompositeStage::execute(...)now builds raster/composite inputs with explicitstate_view/mutation_accessinstead of provider-only stage contracts.- Mutating stage helpers now source bucket writes from
IFrameMutationAccess: reset_render_state_for_frame(...)RasterStage::render_tile_fallback(...)RasterStage::try_reuse_cached_render(...)RasterStage::render_baseline_stage(...)RasterStage::render_painterly_or_baseline_stage(...)render_sorted_splats_with_context(...)- Query-only cull/sort stage paths continue to read through
IFrameStateView.
- Added
- Explicitly preserved for this slice:
- No service-pointer narrowing.
- No debug overlay or painterly direct-facade redesign.
- No sorting-seam API work.
- No public
GaussianSplatRendererfacade behavior change. - Remaining caveat:
- The legacy provider bridge still exists in
RenderFrameContext::state_provider, and_resolve_mutation_access(...)still falls back through that bridge for older callers that have not populated explicit mutation access yet. - Service pointers exposed by
IFrameStateViewremain mutable and are still under the known 1b caveat. - Rollback boundary:
- Revert only slice-15 stage-writer split changes in
gaussian_splat_renderer.h,render_pipeline_stages.h, andrender_pipeline_stages.cpp. - Verification status:
git diff --checkpassed for touched files.- Local phase checks passed via
python3 scripts/refactor_phase_runner.py local-checks --phase 1b.2a --no-regen-architecture. - Native Windows verification passed via
Gaussian Production Gatesonrefactor/gs-renderer-architecture:- Build: pass (Windows self-hosted module-validation lane).
- Guard lane: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions). - Runtime/benchmark gates: pass (runtime harness, world-streaming gate, large-scene benchmark, eviction-churn benchmark).
Phase 1b.2b implementation status (painterly provider-backed bucket reads, slice 16)¶
- Date: 2026-03-24
- Scope applied:
modules/gaussian_splatting/interfaces/painterly_renderer.cpp:- Introduced local
GaussianSplatRenderer::FrameStateProviderinstances in painterly production helpers that already sit on provider-backed buckets. - Rewired
clear_painterly_gpu_resources(...)andupdate_painterly_gpu_resources(...)to mutateSubsystemStatethroughIFrameMutationAccessinstead of direct renderer getters. - Rewired
render_painterly_frame(...)to querySubsystemStatethroughIFrameStateViewfor tile-raster output access. - Rewired
populate_painterly_gbuffer(...)to sourcescene_state,resource_state,streaming_state,sorting_state,subsystem_state,frame_state,performance_state, andjacobian_debugthroughIFrameStateView/IFrameMutationAccessaliases instead of direct renderer getters. - Also moved direct render-device / render-config reads that already had provider seams:
_resolve_tracked_device(...)_update_painterly_texture_tracking(...)_ensure_painterly_composite_resources(...)update_painterly_gpu_resources(...)populate_painterly_gbuffer(...)opacity multiplier- Kept direct access for surfaces that still lack a provider seam in this slice, including
device_state,view_state,tile_renderer_state,debug_state,culling_config, andpainterly_config.
- Introduced local
- Explicitly preserved for this slice:
- No painterly public API redesign.
- No service-pointer narrowing.
- No debug overlay, sorting-seam, or composition-root work.
- No attempt to force non-provider surfaces through the new aliases.
- Remaining caveat:
device_state,view_state,tile_renderer_state,debug_state,culling_config, andpainterly_configremain renderer-direct by design until matching seams exist.- Rollback boundary:
- Revert only slice-16 provider-alias rewiring in
modules/gaussian_splatting/interfaces/painterly_renderer.cpp. - Verification status:
git diff --checkpassed for the slice.
Phase 1b.1 implementation status (query-only callsite migration, slice 2)¶
- Date: 2026-03-23
- Scope applied:
- Additional query-only usages were switched to
IFrameStateViewaliases inmodules/gaussian_splatting/renderer/render_pipeline_stages.cpp:SortStage::execute(...)query helper reads (_get_sort_indices_buffer(...)) now route throughstate_view.RasterCompositeStage::execute(...)query reads (get_output_compositor, cull/color signatures, sort-index buffer helper) now route throughstate_view, while mutating downstream stage pointers still use the existing provider pointer.RasterStage::resolve_painterly_output(...)reads painterly renderer throughstate_view.RasterStage::render_baseline_stage(...)query-only reads (_get_sort_indices_buffer,get_frame_plan) now route throughstate_view.CompositeStage::execute(...)query fetches (get_output_compositor,get_rendering_device) now route throughstate_view.render_sorted_splats_with_context(...)query reads (get_frame_plan,_get_sort_indices_buffer) now route throughstate_view.
- Explicitly preserved for this slice:
- No service-pointer narrowing.
- No debug overlay migration.
- No painterly direct-facade redesign.
- No sorting-seam API work.
- No mutating-stage provider signature changes.
- Rollback boundary:
- Revert only query-only alias/read edits in
render_pipeline_stages.cppintroduced by slice 2 (RP-2). - Verification status:
git diff --checkpassed for the slice.- Native Windows verification passed:
- Build: pass (incremental,
render_pipeline_stages.cpprecompiled). - Guard lane: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions).
- Build: pass (incremental,
Explicit Phase Boundary: gpu_sorting_pipeline.cpp¶
modules/gaussian_splatting/interfaces/gpu_sorting_pipeline.cppis not a Phase1bprovider-migration target.- It remains explicitly deferred to Phase
2+3sorting-seam cleanup because its current coupling is renderer-direct rather thanIFrameStateProvider-direct. - Phase
1bmay document its current read/write surface, but should not expand scope into sorting-pipeline API redesign.
Minimal Composition-Root Abstraction Needed¶
Use a narrow service bundle for sorting-related wiring, without changing behavior:
- Keep existing interfaces:
ISortResultSinkISortBufferHostContext- Add one new execution interface (working name:
ISortExecutionContext) exposing only currently-used execution dependencies: - ensure/get render device for sorting
- access to required sort/frame/performance state
- culler update hooks required by instance sorting path
- sorter refresh hook
- submission-device provider for async/sync readback paths
- Composition-root bundle (working name:
SortingWiringBundle): ISortExecutionContext *execISortBufferHostContext *buffer_hostISortResultSink *result_sinkGPUSortingPipeline *pipelineGPUCuller *gpu_culler- existing cull/error callbacks already used by sorting orchestrator
This is the minimum coherent seam because it matches current dependencies used in gpu_sorting_pipeline.cpp and render_sorting_orchestrator.cpp without introducing speculative abstraction.
Remaining GPUSortingPipeline APIs Coupled To GaussianSplatRenderer¶
Current renderer-dependent APIs/pathways to remove in staged migration:
- Header/API surface:
- ensure_sort_buffers(GaussianSplatRenderer *, uint32_t)
- release_sort_buffers(GaussianSplatRenderer *)
- sort_gaussians_gpu(GaussianSplatRenderer *, const Transform3D &)
- _sort_instance_pipeline(GaussianSplatRenderer &, const Transform3D &)
- Implementation coupling:
- set_sort_result_sink(&renderer) + set_sort_buffer_host_context(&renderer)
- direct reads/writes through renderer state in _sort_instance_pipeline
Phased Refactor Plan¶
Phase 0: Migration Ledger And Dependency Map (Done)¶
- Purpose:
- Establish fresh architecture baseline from current code.
- Freeze factual coupling model before any behavior-affecting refactor.
- Target files:
docs/architecture/generated/*docs/architecture/gaussian-renderer-refactor-memory.md- Exact dependencies:
scripts/generate_architecture_diagrams.py- Compatibility risks:
- Low (analysis/docs only).
- Verification strategy:
- Regeneration succeeds.
- Generated file set complete.
- What must not change:
- Runtime behavior and public API.
- Rollback point:
- Drop generated/doc changes only.
Phase 1a: Read-Only Snapshots For Diagnostics/Monitoring¶
- Purpose:
- Migrate query-only consumers away from broad mutable renderer state access.
- Target files:
modules/gaussian_splatting/core/performance_monitors.cpp- selected query paths in
render_diagnostics_orchestrator.cpp - snapshot DTO/header definitions under
renderer/render_types/*(new or existing location) - Exact dependencies:
- renderer snapshot assembly function(s) in facade
- no mutator access from monitoring call sites
- Compatibility risks:
- stale snapshot risk, missing fields in telemetry/HUD output
- Verification strategy:
- compare monitor values pre/post on same deterministic frame
- run tests that validate diagnostics fields in
test_renderer_pipeline.h - What must not change:
- monitor names, semantics, and published values
- telemetry cadence
- Rollback point:
- keep snapshot types but switch consumers back to direct reads if values regress
Phase 1b: Explicit Mutator APIs For Mixed Consumers + Provider Contract Hardening¶
- Purpose:
- Split read/query interfaces from explicit state mutation commands.
- Remove mutable-from-const provider shape.
- Target files:
modules/gaussian_splatting/renderer/gaussian_splat_renderer.hmodules/gaussian_splatting/renderer/gaussian_splat_renderer.cppmodules/gaussian_splatting/interfaces/debug_overlay_system.cppmodules/gaussian_splatting/interfaces/painterly_renderer.cppmodules/gaussian_splatting/renderer/render_diagnostics_orchestrator.cpp- Exact dependencies:
- new narrow mutator entrypoints on facade or dedicated command interfaces
- separate read-only provider (
constonly) and mutator provider (non-constonly), or equivalent split - Compatibility risks:
- accidental behavior shifts in overlay invalidation/HUD refresh ordering
- painterly route regressions from changed state write sequencing
- Verification strategy:
- existing debug overlay/painterly tests and runtime smoke scenes
- assert no mutable fallback static path remains
- What must not change:
- visible overlay/HUD behavior
- painterly fallback semantics
- facade external API contract
- Rollback point:
- revert provider split and keep explicit mutator wrappers as adapters
Phase 2 + Phase 3 (Coupled): Composition Root Cleanup + Sorting Legacy Renderer-Path Removal¶
- Purpose:
- Remove renderer-centric sorting dependencies while simultaneously cleaning constructor/wiring ownership.
- Avoid introducing temporary composition abstractions that do not reduce coupling.
- Target files:
modules/gaussian_splatting/interfaces/gpu_sorting_pipeline.hmodules/gaussian_splatting/interfaces/gpu_sorting_pipeline.cppmodules/gaussian_splatting/interfaces/gpu_sorting_pipeline_interfaces.hmodules/gaussian_splatting/renderer/render_sorting_orchestrator.h/.cppmodules/gaussian_splatting/renderer/render_streaming_orchestrator.h/.cppmodules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp- Exact dependencies:
ISortResultSink,ISortBufferHostContext, newISortExecutionContext- composition root bundle for sorting wiring
- no direct
GaussianSplatRenderertype in sorting pipeline public API - Compatibility risks:
- sorting fallback route regressions
- async readback timeline/wait semantics regressions
- cross-device resource ownership regressions
- Verification strategy:
- sort correctness checks under CPU fallback and GPU paths
- instance pipeline scenes with async count readback
- targeted tests in
test_renderer_pipeline.haround sorting metrics and fallback flags - What must not change:
- sort output determinism tolerances
- fallback policy behavior and diagnostics fields
- renderer facade entrypoints for external callers
- Rollback points:
- RP1: after adding interface adapters, before orchestrator callsite migration
- RP2: after orchestrator migration, before deleting renderer overloads
- RP3: before removing singleton fallback paths
Phase 2 + Phase 3 implementation status (sorting seam batch 1, slice 19)¶
- Date: 2026-03-24
- Scope applied:
modules/gaussian_splatting/interfaces/gpu_sorting_pipeline.h/.cpp/_interfaces.h:- Removed public/legacy sorting entrypoints that took
GaussianSplatRenderer *orGaussianSplatRenderer &. - Added
SortFrameContextplus explicitset_sort_frame_context(...)/clear_sort_frame_context()so instance sorting reads only the state buckets and execution dependencies it actually needs. _sort_instance_pipeline(...)now executes fromSortFrameContextinstead of reaching through the renderer facade.
- Removed public/legacy sorting entrypoints that took
modules/gaussian_splatting/renderer/render_sorting_orchestrator.cpp:- Added explicit host/sink binding helpers and
SortFrameContextconstruction from the renderer-owned buckets. - Replaced removed
ensure_sort_buffers(renderer, ...),release_sort_buffers(renderer), andsort_gaussians_gpu(renderer, ...)callsites with explicit host/context wiring plus the new context-less pipeline entrypoints. - Both the instance-only fast path and the common GPU-sort path now populate
SortFrameContextbefore dispatch.
- Added explicit host/sink binding helpers and
modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp:- Sorting-pipeline shutdown now binds sink/host explicitly before releasing sort buffers, instead of using the deleted renderer-taking overload.
- Fixes required before accepting this batch:
- Corrected
SortFrameContextbucket types to the renderer-owned types used in the current branch. - Corrected interface include paths in
gpu_sorting_pipeline_interfaces.h(render_frame_context_manager.h,render_performance_types.h,render_state_types.h) so Windows build graph resolution matched the new interface location. - Blocked instance-cache and instance-GPU fast paths while
sorting_state.sorter_needs_rebuildis set, so forced algorithm/capacity changes cannot be bypassed by early returns. - Explicitly preserved for this batch:
- No composition-root callback cleanup yet.
- No debug overlay, painterly, or test-hook redesign.
- No public
GaussianSplatRendererfacade entrypoint changes. - Remaining caveat:
- This closes the renderer-taking sorting API seam, but the broader composition-root cleanup is still pending for the next
2+3batch. - Sorting still uses explicit host/sink/context wiring rather than the final bundled composition-root contract.
- Rollback boundary:
- Revert only the sorting seam batch in:
modules/gaussian_splatting/interfaces/gpu_sorting_pipeline.hmodules/gaussian_splatting/interfaces/gpu_sorting_pipeline.cppmodules/gaussian_splatting/interfaces/gpu_sorting_pipeline_interfaces.hmodules/gaussian_splatting/renderer/render_sorting_orchestrator.cppmodules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp
- Verification status:
git diff --checkpassed for each landed fixup.- Local phase checks passed via
python3 scripts/refactor_phase_runner.py local-checks --phase 2-3 --no-regen-architecture. - Native Windows verification passed via
Gaussian Production Gatesrun23482731572on commit9bc9032b54:- Build: pass.
- Smoke tests: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions). - Runtime harness: pass.
- World-streaming gate: pass.
- Large-scene benchmark gate: pass.
- Eviction-churn benchmark gate: pass.
Phase 2 + Phase 3 implementation status (composition-root batch 2, slice 20)¶
- Date: 2026-03-24
- Scope applied:
modules/gaussian_splatting/renderer/render_streaming_orchestrator.h/.cpp:- Added
RenderStreamingOrchestratorDependencieswith a narrowRuntimePortsbundle for the renderer callbacks this orchestrator still needs during streaming bootstrap and frame execution. - Replaced direct renderer method dispatch for device bootstrap, cull-projection construction/validation, instance-buffer clearing/upload, cull/sort pipeline dispatch, and cull radius/slack lookups with explicit runtime-port calls.
- Stored and validated the runtime-port bundle in the orchestrator constructor so the seam is explicit and constructor-time failures are surfaced early.
- Added
modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp:- Switched streaming orchestrator construction to the dependency bundle form instead of the old raw constructor argument mesh.
- Fixes required before accepting this batch:
- Corrected
RuntimePortsfunction-pointer signatures forvalidate_cull_projection_contract(...)andrun_cull_sort_pipeline_frame(...), including the qualifiedGaussianSplatRenderer::RenderFallbackReasontype, after the first Windows build exposed the mismatch. - Explicitly preserved for this batch:
- No streaming logic redesign.
- No service-pointer narrowing beyond the selected runtime-port calls above.
- No sorting-seam, debug/tooling, painterly, or test-hook work.
- No public
GaussianSplatRendererfacade entrypoint changes. - Remaining caveat:
RenderStreamingOrchestratorstill retains many direct renderer/state interactions outside the new runtime-port bundle. This batch only extracts the constructor/runtime-callback seam; broader orchestrator dependency narrowing remains later-phase work.- Rollback boundary:
- Revert only:
modules/gaussian_splatting/renderer/render_streaming_orchestrator.hmodules/gaussian_splatting/renderer/render_streaming_orchestrator.cppmodules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp
- Verification status:
git diff --checkpassed.- Local phase checks passed via
python3 scripts/refactor_phase_runner.py local-checks --phase 2-3 --no-regen-architecture. - Native Windows verification passed via
Gaussian Production Gatesrun23484521277on commit458951d24c:- Build: pass.
- Smoke tests: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions). - Runtime harness: pass.
- World-streaming gate: pass.
- Large-scene benchmark gate: pass.
- Eviction-churn benchmark gate: pass.
Phase 4: Orchestrator Dependency Narrowing¶
- Purpose:
- Remove remaining broad renderer pointer dependencies from orchestrator internals.
- Target files:
render_streaming_orchestrator.*render_sorting_orchestrator.*- potentially
render_data_orchestrator.*,render_output_orchestrator.*for follow-up narrowing - Exact dependencies:
- small contracts/service bundles injected at construction
- reduced callback surface with explicit ownership
- Compatibility risks:
- initialization order regressions
- null dependency handling regressions
- Verification strategy:
- constructor-time dependency validation
- render-loop smoke + stage metrics sanity checks
- What must not change:
- orchestration order and frame-stage semantics
- Rollback point:
- restore previous constructor signatures while preserving internal refactors that are behavior-neutral
Phase 4 implementation status (output orchestrator batch 1, slice 21)¶
- Date: 2026-03-24
- Scope applied:
modules/gaussian_splatting/renderer/render_output_orchestrator.h/.cpp:- Replaced the old constructor callback/raw-pointer mesh with an explicit
Dependenciesbundle and nestedRuntimePortscontract. - Routed output-path runtime callbacks through explicit ports for device bootstrap, texture-format lookup, viewport-format updates, and GPU-resource creation.
- Switched practical frame/resource bucket access to local
FrameStateProviderview/mutation aliases insiderender_for_view(...),copy_final_texture_to_target(...),commit_to_render_buffers(...), andtest_copy_final_output(...).
- Replaced the old constructor callback/raw-pointer mesh with an explicit
modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp:- Updated output orchestrator construction to use the dependency bundle form.
- Explicitly preserved for this batch:
- No sorting-seam work.
- No debug/tooling or painterly redesign.
- No public
GaussianSplatRendererfacade entrypoint changes. - No attempt to force
view_state,device_state, or render submission paths through speculative new interfaces. - Remaining caveat:
RenderOutputOrchestratorstill reaches throughrendererdirectly forview_state,device_state, test-data presence checks, resource-owner lookup, andrender_gaussians(...). This batch narrows the orchestrator’s constructor/runtime seam and selected state-bucket access; it is not a full ownership inversion.- Follow-up fix after initial acceptance:
- Resolved the viewport-copy status getters against the live compositor from
FrameStateProvider, so the copy path and its status readers observe the same compositor instance if renderer subsystem bindings change. - Rollback boundary:
- Revert only:
modules/gaussian_splatting/renderer/render_output_orchestrator.hmodules/gaussian_splatting/renderer/render_output_orchestrator.cppmodules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp
- Verification status:
git diff --checkpassed.- Local phase checks passed via
python3 scripts/refactor_phase_runner.py local-checks --phase 4 --no-regen-architecture. - Native Windows verification passed via
Gaussian Production Gatesrun23485345156on commitf92dbab666:- Build: pass.
- Smoke tests: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions). - Runtime harness: pass.
- World-streaming gate: pass.
- Large-scene benchmark gate: pass.
- Eviction-churn benchmark gate: pass.
Phase 4 implementation status (state/control orchestrator batch 2, slice 22)¶
- Date: 2026-03-24
- Scope applied:
modules/gaussian_splatting/renderer/render_quality_orchestrator.h/.cpp:- Replaced the raw constructor parameter list with an explicit
Dependenciesbundle and narrowRuntimePortscontract for sorter refresh. - Routed mutable sorting/frame/performance bucket access in
set_max_splats(...),set_quality_preset(...), andcull_for_view(...)through localFrameStateProviderview/mutation aliases instead of direct broad renderer state getters. - Kept
set_quality_preset(...)lazy by only marking sorter rebuild needed; no eager sorter refresh is triggered from that setter.
- Replaced the raw constructor parameter list with an explicit
modules/gaussian_splatting/renderer/render_config_orchestrator.h/.cpp:- Replaced the raw constructor parameter list with a
Dependenciesbundle for renderer, interactive state manager, and painterly renderer wiring.
- Replaced the raw constructor parameter list with a
modules/gaussian_splatting/renderer/render_data_orchestrator.h/.cpp:- Replaced the callback-heavy constructor signature with a
Dependenciesbundle. - Routed selected state/control reads and writes in
set_gaussian_data(...),update_gpu_buffers_with_real_data(...), and static-chunk culler updates through local provider-backed view/mutation access.
- Replaced the callback-heavy constructor signature with a
modules/gaussian_splatting/renderer/render_instancing_orchestrator.h/.cpp:- Replaced the raw constructor parameter list with a
Dependenciesbundle. - Rebound readiness checks, per-instance frame-plan reads, and aggregate frame/sorting/performance writes through explicit provider-backed view/mutation access.
- Resolved the output compositor live from provider-backed state at execution time instead of relying solely on the ctor-captured pointer.
- Replaced the raw constructor parameter list with a
modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp:- Updated constructor wiring for quality, config, data, and instancing orchestrators to the new dependency-bundle forms.
modules/gaussian_splatting/tests/test_renderer_pipeline.h:- Updated the instancing orchestrator test helper to construct the orchestrator via the new
Dependenciesbundle after the constructor surface changed.
- Updated the instancing orchestrator test helper to construct the orchestrator via the new
- Explicitly preserved for this batch:
- No sorting-seam work.
- No debug/tooling redesign.
- No painterly redesign beyond constructor wiring already owned by the config batch surface.
- No broad service-pointer narrowing or composition-root rewrite outside these orchestrator constructor/runtime seams.
- No public
GaussianSplatRendererfacade break. - Remaining caveat:
- This batch narrows selected constructor/runtime state-control dependencies, but it does not fully invert ownership. These orchestrators still rely on renderer-facing services and direct renderer helpers for some device, test-data, and submission paths.
- Follow-up fix after initial attempt:
- Removed an unsafe
const_cast-backedFrameStateProvideruse fromGaussianSplatRenderer::get_async_upload_enabled() constand revertedset_quality_preset(...)to lazy sorter rebuild semantics. - Initial Windows workflow run
23487001647on commit3e183a65dcfailed only at build time becausemodules/gaussian_splatting/tests/test_renderer_pipeline.hstill constructedRenderInstancingOrchestratorwith the old five-argument constructor form. - The batch was fixed by updating that stale test helper to the new
Dependenciesconstruction form in commit1627e30a02. - Rollback boundary:
- Revert only:
modules/gaussian_splatting/renderer/render_quality_orchestrator.hmodules/gaussian_splatting/renderer/render_quality_orchestrator.cppmodules/gaussian_splatting/renderer/render_config_orchestrator.hmodules/gaussian_splatting/renderer/render_config_orchestrator.cppmodules/gaussian_splatting/renderer/render_data_orchestrator.hmodules/gaussian_splatting/renderer/render_data_orchestrator.cppmodules/gaussian_splatting/renderer/render_instancing_orchestrator.hmodules/gaussian_splatting/renderer/render_instancing_orchestrator.cppmodules/gaussian_splatting/renderer/gaussian_splat_renderer.cppmodules/gaussian_splatting/tests/test_renderer_pipeline.h
- Verification status:
git diff --checkpassed for the batch and its follow-up fix.- Local phase checks passed via
python3 scripts/refactor_phase_runner.py local-checks --phase 4 --no-regen-architecture. - Native Windows verification passed via
Gaussian Production Gatesrun23487132952on commit1627e30a02:- Build: pass.
- Smoke tests: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions). - Runtime harness: pass.
- World-streaming gate: pass.
- Large-scene benchmark gate: pass.
- Eviction-churn benchmark gate: pass.
Phase 4 implementation status (resource orchestrator batch 3, slice 23)¶
- Date: 2026-03-24
- Scope applied:
modules/gaussian_splatting/renderer/render_resource_orchestrator.h/.cpp:- Replaced the raw constructor parameter list with an explicit
Dependenciesbundle for renderer, device state, and pipeline-feature storage. - Introduced local
FrameStateProvideraliases ininitialize_shaders(),create_gpu_resources_safe(), andupdate_gpu_pass_metrics_from_tile_renderer()so practical subsystem and performance-bucket reads/writes go through local view/mutation access instead of repeated direct renderer state fan-in. - Narrowed painterly/interactive shader setup and GPU timing metric publication to local provider-backed access where that reduced direct renderer-state reach-through.
- Replaced the raw constructor parameter list with an explicit
modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp:- Updated resource orchestrator construction to the dependency-bundle form.
- Explicitly preserved for this batch:
- No sorting-seam work.
- No diagnostics/debug-tooling redesign.
- No painterly redesign.
- No test-data upload redesign.
- No tile-renderer/rasterizer ownership redesign.
- No public
GaussianSplatRendererfacade break. - Remaining caveat:
RenderResourceOrchestratorstill legitimately uses direct renderer helpers for device/bootstrap operations (ensure_rendering_device, submission/main device access), test-data upload/state, tile-renderer state, and resource-ownership bookkeeping. This batch narrows constructor/runtime dependency surfaces; it does not invert the actual resource-management ownership model.- Rollback boundary:
- Revert only:
modules/gaussian_splatting/renderer/render_resource_orchestrator.hmodules/gaussian_splatting/renderer/render_resource_orchestrator.cppmodules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp
- Verification status:
git diff --checkpassed for the batch.- Local phase checks passed via
python3 scripts/refactor_phase_runner.py local-checks --phase 4 --no-regen-architecture. - Native Windows verification passed via
Gaussian Production Gatesrun23487524729on commitb1a8430808:- Build: pass.
- Smoke tests: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions). - Runtime harness: pass.
- World-streaming gate: pass.
- Large-scene benchmark gate: pass.
- Eviction-churn benchmark gate: pass.
Phase 4 implementation status (diagnostics/debug control-plane batch 4, slice 24)¶
- Date: 2026-03-24
- Scope applied:
modules/gaussian_splatting/renderer/render_debug_state_orchestrator.h/.cpp:- Replaced the raw constructor argument mesh with an explicit
Dependenciesbundle plusRuntimePortsfor anomaly-dump operations that still need renderer-owned behavior (dump_pipeline_trace_to_file,get_resource_owner). - Preserved existing overlay query/command-sink usage while narrowing direct control-plane reach-through to local dependency access.
- Replaced the raw constructor argument mesh with an explicit
modules/gaussian_splatting/renderer/render_diagnostics_orchestrator.h/.cpp:- Replaced the raw constructor argument list with an explicit
Dependenciesbundle plus a narrowRuntimePortscallback for GPU pass metric refresh. - Kept frame-finalize ordering intact while routing the tile-renderer GPU metric refresh through the explicit runtime port instead of a direct renderer call.
- Replaced the raw constructor argument list with an explicit
modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp:- Updated diagnostics/debug orchestrator construction to the dependency-bundle form and wired the explicit runtime ports.
- Explicitly preserved for this batch:
- No sorting-seam redesign.
- No painterly redesign.
- No debug overlay redesign.
- No public
GaussianSplatRendererfacade break. - Remaining caveat:
- The diagnostics/debug orchestrators still legitimately reach renderer-owned live state and services where that remains the real ownership boundary; this batch narrows constructor/control-plane fan-in, it does not relocate those ownership responsibilities.
- Rollback boundary:
- Revert only:
modules/gaussian_splatting/renderer/render_debug_state_orchestrator.hmodules/gaussian_splatting/renderer/render_debug_state_orchestrator.cppmodules/gaussian_splatting/renderer/render_diagnostics_orchestrator.hmodules/gaussian_splatting/renderer/render_diagnostics_orchestrator.cppmodules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp
- Verification status:
git diff --checkpassed for the batch.- Local phase checks passed via
python3 scripts/refactor_phase_runner.py local-checks --phase 4 --no-regen-architecture. - Native Windows verification passed via
Gaussian Production Gatesrun23489071182on commit67f3018406:- Build: pass.
- Smoke tests: pass.
- Module lane: pass (
GaussianSplatting144 tests / 4,066 assertions). - Runtime harness: pass.
- World-streaming gate: pass.
- Large-scene benchmark gate: pass.
- Eviction-churn benchmark gate: pass.
Phase 4 implementation status (diagnostics/debug state-path batch 5, slice 25)¶
- Date: 2026-03-24
- Scope applied:
modules/gaussian_splatting/renderer/render_diagnostics_orchestrator.cpp:- Moved frame/performance/sorting/resource/subsystem reads in production-metrics assembly, render-stats assembly, sort-history helpers, frame-transition bookkeeping, and runtime diagnostic snapshot building onto local
FrameStateProviderview/mutation access. - Preserved frame-finalize ordering while keeping the explicit GPU-metric runtime port and debug overlay query/command seam unchanged.
- Moved frame/performance/sorting/resource/subsystem reads in production-metrics assembly, render-stats assembly, sort-history helpers, frame-transition bookkeeping, and runtime diagnostic snapshot building onto local
modules/gaussian_splatting/renderer/render_debug_state_orchestrator.cpp:- Moved pipeline-trace frame stamping, cull-guardrail state reads, anomaly-dump frame/visible-count reads, and anomaly snapshot device/compositor resolution onto local
FrameStateProviderview/mutation access. - Kept anomaly-dump side effects on the existing runtime ports.
- Moved pipeline-trace frame stamping, cull-guardrail state reads, anomaly-dump frame/visible-count reads, and anomaly snapshot device/compositor resolution onto local
- Explicitly preserved for this batch:
- No sorting-seam redesign.
- No painterly redesign.
- No debug overlay redesign.
- No constructor signature changes.
- No public
GaussianSplatRendererfacade break. - Remaining caveat:
- Direct reads of
view_state,painterly_config, anddebug_configremain where no matching read-only seam exists yet; this batch narrows state/config fan-in without inventing new interfaces just to remove those accesses. - Rollback boundary:
- Revert only:
modules/gaussian_splatting/renderer/render_diagnostics_orchestrator.cppmodules/gaussian_splatting/renderer/render_debug_state_orchestrator.cpp
- Verification status:
git diff --checkpassed for the batch.- Local phase checks passed via
python3 scripts/refactor_phase_runner.py local-checks --phase 4 --no-regen-architecture. - Native Windows verification passed via
Gaussian Production Gatesrun23490508420on commita11f35010c(build, smoke tests, module lane, runtime validation, world-streaming gate, large-scene benchmark, eviction-churn benchmark).
Phase 4 implementation status (sorting bootstrap/benchmark batch 6, slice 26)¶
- Date: 2026-03-24
- Scope applied:
modules/gaussian_splatting/renderer/render_sorting_orchestrator.cpp:- Moved frame/sorting/resource access in
refresh_gpu_sorter(...),initialize_sorting(),run_sort_benchmark(...), andbenchmark_sorting_performance()onto localFrameStateProviderview/mutation access where state buckets are the right seam. - Switched benchmark buffer allocation/device metadata to the local
RenderingDevice *fromIFrameStateView. - Consolidated benchmark queue-free cleanup through a tiny local helper that writes through
IFrameMutationAccessto preserve the existing deletion-queue path.
- Moved frame/sorting/resource access in
- Explicitly preserved for this batch:
- No sorting-seam redesign.
- No
GPUSortingPipelinesignature changes. - No changes to
sort_gaussians_for_view(...),force_sort_for_view(...), or sort-cache helpers. - No painterly/debug overlay/composition-root work.
- No public
GaussianSplatRendererfacade break. - Remaining caveat:
- Direct renderer access remains for non-frame buckets and owned service/control boundaries in these bootstrap paths, including device initialization, performance settings, test-data sizing, and host-context binding. This batch narrows state-bucket fan-in without pretending the whole sorting subsystem is decoupled.
- Rollback boundary:
- Revert only:
modules/gaussian_splatting/renderer/render_sorting_orchestrator.cpp
- Verification status:
git diff --checkpassed for the batch.- Local phase checks passed via
python3 scripts/refactor_phase_runner.py local-checks --phase 4 --no-regen-architecture. - Native Windows verification passed via
Gaussian Production Gatesrun23491356476on commitf09286a0cb(build, smoke tests, module lane, runtime validation, world-streaming gate, large-scene benchmark, eviction-churn benchmark).
Phase 5: Lock Down Mutable Renderer State Access¶
- Purpose:
- remove/deny broad mutable
get_*_state()usage outside sanctioned mutator surfaces. - Target files:
- facade headers + main mutator consumers + any remaining offenders from ledger
- Exact dependencies:
- read-only snapshots + explicit command surfaces already in place
- Compatibility risks:
- test breakage where internals were mutated directly
- Verification strategy:
- compile-time failures become migration checklist
- targeted unit/integration test run
- What must not change:
- external facade behavior
- Rollback point:
- temporarily re-enable adapter methods with deprecation guards if migration gaps remain
Phase 5 debug-state slice¶
- Date: 2026-03-24
- Scope applied:
modules/gaussian_splatting/renderer/render_debug_state_orchestrator.cpp:- Pipeline-trace event gating now uses the orchestrator's local debug-config state instead of re-reading
renderer->get_debug_config()at the helper entry. - Cull-guardrail pose hashing now uses the public camera-transform facade instead of direct
view_statereach-through. - Tile overflow summary helpers (
get_overflow_tile_count(),get_clamped_records(),get_aggregated_count(),get_overflow_stats()) now live behindRenderDebugStateOrchestratorinstead of reaching throughGaussianSplatRenderertile-renderer state in the facade. - Pipeline-trace snapshot assembly now lives behind
RenderDebugStateOrchestrator; the renderer facade is now a thin delegate for snapshot/json/file-dump access.
- Pipeline-trace event gating now uses the orchestrator's local debug-config state instead of re-reading
- Explicitly preserved for this slice:
- No diagnostics lock-down.
- No painterly changes.
- No sorting-seam changes.
- No broad renderer/provider hardening.
- Rollback boundary:
- Revert only this debug-state batch in
render_debug_state_orchestrator.handrender_debug_state_orchestrator.cpp. - Verification status:
git diff --checkpassed for touched files.- Local phase checks passed via
python3 scripts/refactor_phase_runner.py local-checks --phase 5 --no-regen-architecture. - Native Windows verification passed via
Gaussian Production Gatesrun23499067202on commit8ec35e4a79(build, smoke tests, module lane, runtime validation, world-streaming gate, large-scene benchmark, eviction-churn benchmark).
Phase 6: Optional Cleanup Of Thin Config-Style Wrappers¶
- Purpose:
- remove temporary wrappers that no longer carry architectural value after coupling reduction.
- Target files:
- only wrappers proven redundant by prior phases
- Exact dependencies:
- completion of phases 1-5
- Compatibility risks:
- low if constrained to dead/duplicative wrappers
- Verification strategy:
- no public API diff
- no behavior diff in diagnostics/tests
- What must not change:
- no semantic changes disguised as cleanup
- Rollback point:
- restore removed wrappers if any downstream consumer still relies on them
Phase 1b.3 implementation status (debug query/command seam batch, slice 17)¶
- Date: 2026-03-24
- Scope applied:
modules/gaussian_splatting/interfaces/debug_overlay_system.h/.cpp:- Introduced explicit
DebugOverlayQueryViewandDebugOverlayCommandSinkseam structs with builder helpers onDebugOverlaySystem. - Kept legacy
get_*/set_*renderer helpers as compatibility delegates. - Query view exposes overlay options and HUD/tile-density snapshot access used by the debug-facing orchestrators.
- Command sink forwards overlay/HUD invalidation and flag/opacity mutations through the existing compatibility helpers.
- Introduced explicit
modules/gaussian_splatting/interfaces/debug_overlay_macros.h:- Debug orchestrator setter macro now uses
build_command_sink(renderer)instead of direct legacy renderer helper calls.
- Debug orchestrator setter macro now uses
modules/gaussian_splatting/renderer/render_debug_state_orchestrator.cpp:- Debug option application now reads from
build_query_view(renderer)/DebugOverlayOptionsrather than directdebug_overlay_systemgetters. - Direct debug-overlay setter paths now use
build_command_sink(renderer)for overlay/HUD mutation.
- Debug option application now reads from
modules/gaussian_splatting/renderer/render_diagnostics_orchestrator.cpp:- Render-stat aggregation now sources debug overlay options, HUD lines, and tile-density values from the new query view.
- HUD invalidation / rebuild paths now use the new command sink overloads.
- Explicitly preserved for this slice:
- No sorting-seam work.
- No composition-root work.
- No painterly redesign.
- No broad service narrowing beyond the explicit debug overlay seam.
- Remaining caveat:
- The legacy renderer helpers remain available as compatibility delegates for holdout callsites outside this batch.
- Rollback boundary:
- Revert only the
debug_overlay_systemseam wrapper additions and the orchestrator callsite rewiring in the files above. - Verification status:
git diff --checkpassed for the batch.- Local phase checks passed via
python3 scripts/refactor_phase_runner.py local-checks --phase 1b.3 --no-regen-architecture. - Native Windows verification passed via
Gaussian Production Gatesrun23479912351on commit349347af77(build, smoke tests, module lane, runtime validation, world-streaming gate, large-scene benchmark, eviction-churn benchmark).
Phase 1b.4 implementation status (test-hook migration batch, slice 18)¶
- Date: 2026-03-24
- Scope applied:
modules/gaussian_splatting/renderer/gaussian_splat_renderer.h/.cpp:- Added explicit test-only seams for streaming-system reset/readiness and output-compositor access (
test_release_current_streaming_system(),test_has_current_streaming_system(),test_get_output_compositor()).
- Added explicit test-only seams for streaming-system reset/readiness and output-compositor access (
modules/gaussian_splatting/interfaces/output_compositor.h/.cpp:- Added a narrow test-only hook to reset viewport-copy bookkeeping without mutating
get_cache_state()directly.
- Added a narrow test-only hook to reset viewport-copy bookkeeping without mutating
modules/gaussian_splatting/tests/test_renderer_pipeline.h:- Replaced direct streaming-system mutation with the explicit renderer test hooks.
- Replaced direct
get_subsystem_state().output_compositoraccess with the explicit test-named renderer seam. - Replaced direct output-cache mutation with the compositor test hook.
modules/gaussian_splatting/tests/test_gaussian_splat_node.cpp:- Replaced
get_scene_state().gaussian_dataassertions with the stable publicget_gaussian_data()facade accessor.
- Replaced
- Explicitly preserved for this slice:
- No production behavior changes.
- No sorting-seam work.
- No composition-root work.
- No provider lock-down yet.
- Remaining caveat:
- Tests still exercise
OutputCompositordirectly through an explicit test seam; this is intentional for1b.4and narrower than the previous subsystem-state reach-through. - Rollback boundary:
- Revert only the explicit test-seam additions in renderer/output compositor and the matching test callsite rewrites.
- Verification status:
git diff --checkpassed for the batch.- Local phase checks passed via
python3 scripts/refactor_phase_runner.py local-checks --phase 1b.4 --no-regen-architecture. - Native Windows verification passed via
Gaussian Production Gatesrun23480421484on commitf659aeff64(build, smoke tests, module lane, runtime validation, world-streaming gate, large-scene benchmark, eviction-churn benchmark).
Phase 1b.5 implementation status (provider lock-down completion batch, slice 19)¶
- Date: 2026-03-24
- Scope applied:
modules/gaussian_splatting/renderer/gaussian_splat_renderer.h/.cpp:- Removed the legacy
IFrameStateProvidercompatibility surface. - Promoted
FrameStateProviderto implementIFrameStateView+IFrameMutationAccessdirectly with explicit*_view()/*_mut()methods. - Removed
RenderFrameContext::state_provider; stage-entry contexts now carry only explicitstate_viewandmutation_access. - Updated renderer entry paths that create frame contexts to populate the explicit view/mutation seams directly.
- Removed the legacy
modules/gaussian_splatting/renderer/render_pipeline_stages.cpp:- Removed the
const_cast-based legacy provider bridge from_resolve_mutation_access(...). - Rebound frame-entry execution to explicit view/mutation seams only.
- Final runtime fix: when
execute_frame_entry(...)copiesRenderFrameContext, it now always rebinds both seams against the copieddepsobject before raster/composite execution soframe_planand state pointers cannot go stale.
- Removed the
modules/gaussian_splatting/renderer/render_instancing_orchestrator.cpp:- Updated instanced render entry to populate explicit
state_view+mutation_accesson per-instance frame contexts.
- Updated instanced render entry to populate explicit
- Explicitly preserved for this slice:
- No sorting-seam work.
- No composition-root cleanup.
- No debug/tooling redesign.
- No painterly redesign.
- No public
GaussianSplatRendererfacade break. - Remaining caveat:
IFrameStateViewno longer hides mutable state buckets behindconst, but it still exposes mutable service pointers (OutputCompositor *,GPUCuller *,PainterlyRenderer *,GPUSortingPipeline *,RenderingDevice *) until later seam narrowing.- Rollback boundary:
- Revert only the explicit provider-lockdown changes in
gaussian_splat_renderer.h,gaussian_splat_renderer.cpp,render_pipeline_stages.cpp, andrender_instancing_orchestrator.cpp. - Verification status:
git diff --checkpassed for the batch.- Local phase checks passed via
python3 scripts/refactor_phase_runner.py local-checks --phase 1b.5 --no-regen-architecture. - Initial Windows workflow run
23481131357on commit30fbd0efa3failed only in the world-streaming runtime gate; the batch was fixed by rebinding frame-entry seams to the copiedRenderFrameContext::depsinrender_pipeline_stages.cpp. - Native Windows verification passed via
Gaussian Production Gatesrun23481647454on commit620996d67e(build, smoke tests, module lane, runtime validation, world-streaming gate, large-scene benchmark, eviction-churn benchmark).
Tests That Mutated Internals And The Current Replacement Hooks¶
Replaced in 1b.4:
- Streaming-system teardown in test_renderer_pipeline.h now uses GaussianSplatRenderer::test_release_current_streaming_system() and test_has_current_streaming_system().
- Output-compositor reach-through in test_renderer_pipeline.h now uses GaussianSplatRenderer::test_get_output_compositor().
- Viewport-copy cache resets in test_renderer_pipeline.h now use OutputCompositor::test_reset_last_viewport_copy_state().
- Scene-data assertions in test_gaussian_splat_node.cpp now use the stable public GaussianSplatRenderer::get_gaussian_data() facade.
Rules for remaining test seams: - keep hooks test-only and explicitly named - do not expose broad mutable production state - preserve existing test intent and assertions - prefer read-only snapshots over additional subsystem reach-through if more output-compositor coverage is needed later
Non-Negotiables During Implementation¶
GaussianSplatRendererremains the stable public facade.- No orchestrator collapse back into renderer.
- No full rewrite.
- No “interface explosion”; add contracts only where coupling is proven.
- Diagnostics/HUD/performance monitors/tests/editor integration remain first-class compatibility surfaces.
- If a phase touches too many consumers at once, stop and resequence instead of pushing through.
Decision Log (Why This Sequence)¶
- Start with fresh generated artifacts because stale architecture reports lead to wrong sequencing.
- Split phase 1 into
1aand1bbecause observability consumers are mixed (query + mutation). - Handle mutable-from-const provider contracts early because they undermine all later snapshot guarantees.
- Couple composition-root cleanup with sorting seam removal so constructor cleanup tracks real dependency direction change.
- Delay strict mutable access lock-down until replacement seams and test hooks exist, to avoid broad breakage.
Implementation Entry Criteria¶
Before any code phase starts: - update this memory file with phase-specific migration map and selected consumer set - list exact callsites being moved in that phase - identify read-only vs mutator consumers explicitly - define rollback commit boundary before first edit
Phase 4.1 Implementation Status (sorting bootstrap + diagnostics only)¶
Scope applied¶
modules/gaussian_splatting/renderer/render_sorting_orchestrator.cpp- Bootstrapping and benchmark/diagnostic entry points now bind the renderer-owned frame buckets through the existing
FrameStateProviderseam where it already fits:refresh_gpu_sorterinitialize_sortingrun_sort_benchmarkbenchmark_sorting_performance
- The batch keeps backoff timing, sorter rebuild flow, benchmark math, logging, and cleanup behavior intact.
- A tiny local helper centralizes benchmark buffer queue-free so the resource cleanup path stays identical.
modules/gaussian_splatting/renderer/render_sorting_orchestrator.h- No signature changes were required for this batch.
docs/architecture/gaussian-renderer-refactor-memory.md- Added this batch note and rollback boundary.
Explicitly preserved¶
- No changes to
sort_gaussians_for_view. - No changes to
force_sort_for_view. - No cache-helper changes.
- No
GPUSortingPipelinesignature changes. - No sorting-seam redesign.
- No painterly, debug-overlay, or composition-root changes.
Caveat¶
- This is dependency narrowing, not full sorting decoupling.
- The target functions still use direct renderer access for things the current provider does not expose, such as device initialization and non-frame buckets like performance settings and test data.
- That is deliberate; I did not widen the seam just to remove every renderer getter.
Rollback boundary¶
- Revert only:
modules/gaussian_splatting/renderer/render_sorting_orchestrator.cppdocs/architecture/gaussian-renderer-refactor-memory.md- If this batch regresses, do not roll back unrelated renderer or pipeline work.
Phase 4.2 Implementation Status (sorting execution dependency narrowing, slice 27)¶
Scope applied¶
modules/gaussian_splatting/renderer/render_sorting_orchestrator.cpp- Routed
sort_gaussians_for_view(...)through a localFrameStateProviderplus explicitIFrameStateView/IFrameMutationAccessaliases. - Moved route-UID publication, visible-count publication, and sort-metric resets/timings onto local frame/perf/debug references, with tiny local helpers for the repeated metric/count updates.
- Preserved strict-global-sort fallback behavior, cache reuse, cull-signature tracking, and the existing device/buffer ownership flow.
- Kept
force_sort_for_view(...)focused on projection/viewport preparation and the streaming fallback path; it now uses local view-state aliasing for the read side without widening the seam. docs/architecture/gaussian-renderer-refactor-memory.md- Added this batch note and verification status.
Explicitly preserved¶
- No
GPUSortingPipelinesignature changes. - No sorting-seam redesign.
- No painterly/debug overlay/composition-root work.
- No broad new interface just to remove every remaining renderer getter.
Caveat¶
force_sort_for_view(...)still reaches throughrendererfor the current view-state and streaming orchestrator because the existing frame provider seam does not expose a view-state contract. That is intentional for this slice.
Rollback boundary¶
- Revert only:
modules/gaussian_splatting/renderer/render_sorting_orchestrator.cppdocs/architecture/gaussian-renderer-refactor-memory.md
Verification status¶
git diff --checkpassed.python3 scripts/refactor_phase_runner.py local-checks --phase 4 --no-regen-architecturepassed.- Native Windows verification passed via
Gaussian Production Gatesrun23491967749on commita931f3a1e6(build, smoke tests, module lane, runtime validation, world-streaming gate, large-scene benchmark, eviction-churn benchmark).
Phase 4.3 Implementation Status (sorting helper/cache support-path narrowing, slice 28)¶
Scope applied¶
modules/gaussian_splatting/renderer/render_sorting_orchestrator.cpp- Narrowed
_set_instance_sort_inputs(...)to consume explicit instance-pipeline buffers plus the render device from the existing frame-state seam instead of pulling the device fromrenderer. - Narrowed
_build_sort_frame_context(...)to buildSortFrameContextfrom the explicitIFrameStateView/IFrameMutationAccessseams and a passed-in view-state reference, instead of reading all frame/perf/device fields fromrenderer. - Routed instance-sort cache hit/miss publication through a local
FrameStateProviderinside the cache helper so cache metrics no longer write torenderer->get_performance_state()directly. - Kept route UID, visible-count, timing, strict-global-sort, cache-reuse, and device/buffer semantics unchanged.
docs/architecture/gaussian-renderer-refactor-memory.md- Added this batch note and verification status.
Explicitly preserved¶
- No
GPUSortingPipelinesignature changes. - No composition-root work.
- No diagnostics/debug overlay work.
- No test-hook changes.
- No broad renderer facade redesign.
Caveat¶
- The residual instance-pipeline buffer lookup in
sort_gaussians_for_view(...)still comes fromrendererbecause the current frame-state seam does not expose instance buffer ownership. That is intentionally outside the seam narrowed in this slice.
Rollback boundary¶
- Revert only:
modules/gaussian_splatting/renderer/render_sorting_orchestrator.cppdocs/architecture/gaussian-renderer-refactor-memory.md
Verification status¶
git diff --checkpassed.python3 scripts/refactor_phase_runner.py local-checks --phase 4 --no-regen-architecturepassed.- Native Windows verification passed via
Gaussian Production Gatesrun23492944688on commit1e1c5d28eb(build, smoke tests, module lane, runtime validation, world-streaming gate, large-scene benchmark, eviction-churn benchmark).
Phase 4.4 Implementation Status (sorting bootstrap/benchmark lifecycle narrowing, slice 29)¶
Scope applied¶
modules/gaussian_splatting/renderer/render_sorting_orchestrator.h/.cpp- Introduced an explicit
Dependenciesbundle for the sorting orchestrator bootstrap and benchmark lifecycle paths. - Routed sorter refresh, initialization, and benchmark device bootstrap through explicit
performance_settings,test_data_state,device_state, andensure_rendering_devicedependencies instead of repeated renderer reach-through in those paths. - Preserved sorter rebuild, benchmark timing/output, and failure/fallback behavior.
modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp- Updated sorting orchestrator construction to supply the explicit lifecycle dependencies.
Explicitly preserved¶
- No
GPUSortingPipelinesignature changes. - No changes to the already-closed core sort execution path beyond constructor wiring.
- No route UID behavior changes.
- No diagnostics/debug overlay work.
- No composition-root redesign.
- No resource/output/painterly/quality/test changes.
Caveat¶
- This batch narrows bootstrap/benchmark lifecycle fan-in, not the remaining execution-path reads that still legitimately depend on renderer-owned services and buffers.
Rollback boundary¶
- Revert only:
modules/gaussian_splatting/renderer/render_sorting_orchestrator.hmodules/gaussian_splatting/renderer/render_sorting_orchestrator.cppmodules/gaussian_splatting/renderer/gaussian_splat_renderer.cppdocs/architecture/gaussian-renderer-refactor-memory.md
Verification status¶
git diff --checkpassed.python3 scripts/refactor_phase_runner.py local-checks --phase 4 --no-regen-architecturepassed.- Native Windows verification passed via
Gaussian Production Gatesrun23495754350on commit72d89b1884(build, smoke tests, module lane, runtime validation, world-streaming gate, large-scene benchmark, eviction-churn benchmark).
Phase 4.5 Implementation Status (output residual dependency narrowing, slice 30)¶
Scope applied¶
modules/gaussian_splatting/renderer/render_output_orchestrator.h/.cpp- Added explicit
view_stateandtest_data_statedependencies so output-path camera/viewport bookkeeping and test-data emptiness checks no longer reach through broad renderer getters. - Added output-specific runtime ports for
get_resource_owner(...)andrender_gaussians(...)sorender_for_view(...)narrows resource-owner lookup and dispatch through explicit behavior seams instead of direct renderer helper calls. - Switched
copy_final_texture_to_target(...),render_for_view(...), andtest_copy_final_output(...)to use the explicit state pointers and provider-backed rendering-device lookup for compositor initialization. modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp- Updated output orchestrator construction to supply the narrowed output-state pointers and runtime ports.
Explicitly preserved¶
- No sorting-seam work.
- No resource-orchestrator changes.
- No painterly redesign.
- No public
GaussianSplatRendererfacade entrypoint changes. - No Phase 5 mutable-access lockdown work.
Caveat¶
- This batch narrows the residual output seam, but it intentionally leaves painterly pass-graph use, GPU culler interaction, and renderer-owned viewport-format behavior on their current contracts.
Rollback boundary¶
- Revert only:
modules/gaussian_splatting/renderer/render_output_orchestrator.hmodules/gaussian_splatting/renderer/render_output_orchestrator.cppmodules/gaussian_splatting/renderer/gaussian_splat_renderer.cppdocs/architecture/gaussian-renderer-refactor-memory.md
Verification status¶
git diff --checkpassed.python3 scripts/refactor_phase_runner.py local-checks --phase 4 --no-regen-architecturepassed.- Native Windows verification passed via
Gaussian Production Gatesrun23496475589on commit69ade68383(build, smoke tests, module lane, runtime validation, world-streaming gate, large-scene benchmark, eviction-churn benchmark).
Phase 4.6 Implementation Status (resource dependency-bundle narrowing, slice 31)¶
Scope applied¶
modules/gaussian_splatting/renderer/render_resource_orchestrator.h/.cpp- Added an explicit dependency bundle for resource setup paths:
performance_settings,painterly_config,debug_config,test_data_state,tile_renderer_state, andsubsystem_state. - Added resource-specific runtime ports for renderer-owned behavior that still belongs on the facade:
ensure_rendering_device(...),get_submission_device(),get_main_rendering_device(),refresh_gpu_sorter(...),track_resource_owner(...), andfree_owned_resource(...). - Rewired
initialize_shaders(),create_gpu_resources_safe(), andload_graphics_shader()to use those explicit dependencies and ports instead of repeated directrenderer->get_*reach-through. - Kept
update_gpu_pass_metrics_from_tile_renderer()bounded to the current metric seam; it still uses local provider access where metric mutation remains the correct contract. modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp- Updated resource orchestrator construction to supply the narrowed dependency bundle and runtime ports.
Explicitly preserved¶
- No sorting-seam changes.
- No painterly redesign.
- No debug-overlay redesign.
- No Phase 5 mutable-access lock-down.
- No public
GaussianSplatRendererfacade entrypoint changes.
Caveat¶
- This batch narrows the large resource-setup fan-in, but it does not invert ownership for painterly or interactive subsystem behavior. Calls that inherently require the renderer facade still use the explicit runtime ports or existing subsystem APIs.
update_gpu_pass_metrics_from_tile_renderer()still uses local provider access for metric mutation and rasterizer timing access; that seam is intentionally left for the later hardening phase.
Rollback boundary¶
- Revert only:
modules/gaussian_splatting/renderer/render_resource_orchestrator.hmodules/gaussian_splatting/renderer/render_resource_orchestrator.cppmodules/gaussian_splatting/renderer/gaussian_splat_renderer.cppdocs/architecture/gaussian-renderer-refactor-memory.md
Verification status¶
git diff --checkpassed.python3 scripts/refactor_phase_runner.py local-checks --phase 4 --no-regen-architecturepassed.- Native Windows verification passed via
Gaussian Production Gatesrun23497309698on commit74aa214511(build, smoke tests, module lane, runtime validation, world-streaming gate, large-scene benchmark, eviction-churn benchmark).
Phase 5.1 Implementation Status (quality-path mutable-access lockdown, slice 32)¶
Scope applied¶
modules/gaussian_splatting/renderer/render_quality_orchestrator.h/.cpp- Added explicit quality-path dependencies for
test_data_stateand runtime ports fortrack_resource_owner(...),get_streaming_state_mut(), andget_streaming_state_view(). - Rewired
cull_for_view(...)so test-data input and GPU-buffer ownership tracking no longer reach through direct renderer getters/helpers. - Moved quality/streaming control behavior into the orchestrator for:
set_cull_radius_multiplier(...)set_cull_frustum_plane_slack(...)set_async_upload_enabled(...)get_async_upload_enabled()
modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp- Updated quality orchestrator construction to supply the new explicit dependencies/runtime ports.
- Simplified the corresponding renderer wrapper methods so they delegate to the orchestrator instead of mutating streaming internals through
IFrameStateView.
Explicitly preserved¶
- No painterly changes.
- No diagnostics/debug-state changes.
- No sorting-seam changes.
- No public
GaussianSplatRendererfacade API changes. - No whole-phase renderer/provider lock-down yet.
Caveat¶
- This is the first bounded Phase 5 enforcement slice, not the final lock-down. It removes the quality-path mutation-through-view pattern and direct quality-path test-data/resource-owner reach-through, but other consumers still retain their own residual mutable access and will need later Phase 5 slices.
- Streaming operations still route through explicit runtime ports backed by the renderer facade; that is intentional for this batch so behavior stays stable while ownership hardening proceeds incrementally.
Rollback boundary¶
- Revert only:
modules/gaussian_splatting/renderer/render_quality_orchestrator.hmodules/gaussian_splatting/renderer/render_quality_orchestrator.cppmodules/gaussian_splatting/renderer/gaussian_splat_renderer.cppdocs/architecture/gaussian-renderer-refactor-memory.md
Verification status¶
git diff --checkpassed.python3 scripts/refactor_phase_runner.py local-checks --phase 5 --no-regen-architecturepassed.- Native Windows verification passed via
Gaussian Production Gatesrun23497924273on commit3110e29fdd(build, smoke tests, module lane, runtime validation, world-streaming gate, large-scene benchmark, eviction-churn benchmark).
Phase 5.2 Implementation Status (data/bootstrap narrowing, slice 33)¶
Scope applied¶
modules/gaussian_splatting/renderer/render_data_orchestrator.h/.cpp- Added explicit data/bootstrap dependencies for
debug_config,performance_settings, and the streaming chunk-radius cull config. - Added a narrow runtime port for
invalidate_cached_render(). - Rewired
_is_data_orchestrator_log_enabled(...),set_gaussian_data(...), andupdate_gpu_buffers_with_real_data()to use those explicit dependencies instead of direct renderer getter reach-through for log gating, cache invalidation, max-streamed budgeting, and streaming radius setup. modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp- Updated data orchestrator construction to supply the narrowed dependency bundle and runtime port.
Explicitly preserved¶
- Reset ordering in
set_gaussian_data(...). - Dynamic asset register/unregister behavior.
- Streaming bootstrap and
visible_splat_countreset semantics. - Existing acquire/release callbacks and renderer facade behavior.
- No sorting-seam, painterly, or debug-overlay redesign.
Caveat¶
update_gpu_buffers_with_real_data()still uses the local frame/provider seam for scene and subsystem access where that remains the right contract; this batch intentionally narrows the bootstrap/config fan-in without changing ownership boundaries more broadly.
Rollback boundary¶
- Revert only:
modules/gaussian_splatting/renderer/render_data_orchestrator.hmodules/gaussian_splatting/renderer/render_data_orchestrator.cppmodules/gaussian_splatting/renderer/gaussian_splat_renderer.cppdocs/architecture/gaussian-renderer-refactor-memory.md
Verification status¶
git diff --checkpassed.python3 scripts/refactor_phase_runner.py local-checks --phase 5 --no-regen-architecturepassed.- Native Windows verification passed via
Gaussian Production Gatesrun23502430431on commit923dabc985(build, smoke tests, module lane, runtime validation, world-streaming gate, large-scene benchmark, eviction-churn benchmark). - Follow-up fix commits were required after earlier Windows-only failures:
e563238383fix(data): use direct config types in orchestrator deps923dabc985fix(data): defer runtime port default binding
Phase 5.3 Implementation Status (diagnostics stats-query narrowing, slice 34)¶
Scope applied¶
modules/gaussian_splatting/renderer/render_diagnostics_orchestrator.h/.cpp- Added narrow runtime ports for painterly-config, view-state, debug-config, and resource-owner resolution used by
build_render_stats(). - Rewired
build_render_stats()query reads to use those runtime ports instead of direct renderer getter reach-through for painterly flags, camera/view telemetry, binning-counter gate checks, and sort-preview buffer owner lookup. - Added constructor validation for the new runtime ports so the narrowed query path cannot silently dereference missing bindings.
Explicitly preserved¶
finalize_frame_metrics()ordering and mutation behavior.get_runtime_diagnostic_snapshot()behavior and external diagnostics payload shape.- Existing stats keys, monitor naming, route UID reporting, and renderer facade behavior.
- No sorting-seam redesign, painterly redesign, or debug-overlay redesign.
Caveat¶
- This slice narrows the
build_render_stats()query fan-in only. Diagnostics still owns mixed query/mutation behavior in finalize/runtime-report paths where that is still the correct orchestrator responsibility.
Rollback boundary¶
- Revert only:
modules/gaussian_splatting/renderer/render_diagnostics_orchestrator.hmodules/gaussian_splatting/renderer/render_diagnostics_orchestrator.cppdocs/architecture/gaussian-renderer-refactor-memory.md
Verification status¶
git diff --checkpassed before checkpoint commit.python3 scripts/refactor_phase_runner.py local-checks --phase 5 --no-regen-architecturepassed on the diagnostics checkpoint.- Native Windows verification passed as part of
Gaussian Production Gatesrun23502430431on commit923dabc985(the verified branch head includes diagnostics checkpointed062e5570plus the follow-up Windows-only data fixes above).
Phase 5 Closeout Assessment¶
Result¶
- Phase 5 is treated as effectively complete after slices 32-34.
- No additional bounded Phase 5 consumer batch is justified right now.
Reasoning¶
- Re-audit of
modules/gaussian_splatting/interfaces/painterly_renderer.cppshows the largest remaining direct facade reads are mostly seam-blocked rather than honestly removable without new abstraction churn. - The one realistic residual win is the device/resource-owner path, but by itself it is too narrow to justify another full phase-sized patch and Windows gate.
- Remaining broad facade-owner bridge work now looks more like optional Phase 6 cleanup / owner hardening than another Phase 5 consumer migration.
Deferred residuals¶
modules/gaussian_splatting/interfaces/painterly_renderer.cpp- Direct
get_painterly_config()/get_view_state()/get_culling_config()/get_debug_state()reads remain where no materially narrower seam exists yet. - Resource-owner/device selection calls remain candidates for future cleanup if they can be grouped with a broader owner-bridge simplification.
modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp- Broad facade-owner pass-through wiring remains, but that is now Phase 6 / cleanup territory rather than a Phase 5 consumer batch.
Phase 6.1 Implementation Status (config invalidation cleanup)¶
Scope applied¶
modules/gaussian_splatting/renderer/render_config_orchestrator.h/.cpp- Added a narrow runtime port for
invalidate_cached_render(). - Rewired
set_opacity_multiplier()andset_color_grading()to invalidate cached render state through that runtime port instead of direct renderer method calls. - Added constructor validation for the runtime port.
modules/gaussian_splatting/renderer/gaussian_splat_renderer.cpp- Updated config orchestrator construction to supply the invalidation runtime port.
Explicitly preserved¶
- Existing config ownership inside
RenderConfigOrchestrator. - Interactive-state behavior and fallback logic.
- Painterly-config mutation behavior and pass-graph reset behavior.
- External renderer facade behavior and script/API names.
Caveat¶
- This is a narrow owner-bridge cleanup only. It does not remove the broader facade pass-through surface, and it intentionally avoids cosmetic wrapper churn with no measurable coupling reduction.
Rollback boundary¶
- Revert only:
modules/gaussian_splatting/renderer/render_config_orchestrator.hmodules/gaussian_splatting/renderer/render_config_orchestrator.cppmodules/gaussian_splatting/renderer/gaussian_splat_renderer.cppdocs/architecture/gaussian-renderer-refactor-memory.md
Verification status¶
git diff --checkpassed.python3 scripts/refactor_phase_runner.py local-checks --phase 6 --no-regen-architecturepassed.- Native Windows verification passed via
Gaussian Production Gatesrun23504205325on commit61c1088ffa(build, smoke tests, module lane, runtime validation, world-streaming gate, large-scene benchmark, eviction-churn benchmark).
Overall Completion Assessment¶
Result¶
- The planned refactor is treated as complete through all non-optional phases.
- Optional Phase 6 cleanup produced one real seam reduction (
render_config_orchestratorcached-render invalidation). - No further cleanup batch is justified right now without dropping below the “real payoff” threshold.
Remaining optional residuals¶
- Thin facade-owner pass-throughs in
gaussian_splat_renderer.cppthat mainly preserve API shape. - Painterly direct config/view/debug reads where no materially narrower seam exists yet.
- Miscellaneous wrapper removal only if it can be bundled with a future owner-bridge simplification instead of standalone churn.