fix(rendering): reconcile shadow roots from live runtime

Recover ordinary live roots from LiveEntityRuntime's canonical active spatial workset instead of relying on already-retained derived records. Keep attached children callback-authoritative, cache immutable selection geometry fingerprints, and pin zero-allocation retained update paths with regression tests.

Release gate: 3,733 App tests / 3 skips; 8,217 complete-solution tests / 5 skips.

Co-Authored-By: OpenAI Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-24 22:45:14 +02:00
parent 056bbd4efd
commit 91463db551
7 changed files with 272 additions and 15 deletions

View file

@ -25,6 +25,7 @@ internal sealed class LiveRenderProjectionJournal : ILiveRenderProjectionSink
private readonly LiveEntityRuntime _runtime;
private readonly RenderProjectionJournal _journal;
private readonly Dictionary<uint, TrackedProjection> _byLocalId = [];
private readonly List<LiveEntityRecord> _activeRootScratch = [];
private readonly List<TrackedProjection> _activeScratch = [];
public LiveRenderProjectionJournal(
@ -107,10 +108,34 @@ internal sealed class LiveRenderProjectionJournal : ILiveRenderProjectionSink
/// </summary>
public void SynchronizeActiveSources()
{
// The canonical live-runtime workset is the source of truth for world
// roots. Walking only this journal's already-tracked values would make
// a missed/reordered derived callback permanent and prevent shadow
// comparison from converging after a same-location revisit.
_runtime.CopySpatialRootObjectRecordsTo(_activeRootScratch);
for (int i = 0; i < _activeRootScratch.Count; i++)
{
LiveEntityRecord record = _activeRootScratch[i];
if (!record.ResourcesRegistered
|| record.WorldEntity is not { } entity
|| !_runtime.IsCurrentSpatialRootObject(record))
{
continue;
}
Upsert(record, entity, record.IsSpatiallyVisible);
}
// Attached children are not members of the ordinary root workset.
// Their exact EntityReady/pose/removal callbacks remain authoritative;
// synchronization only refreshes children whose attachment projection
// is still retained by this derived scene.
_activeScratch.Clear();
foreach (TrackedProjection tracked in _byLocalId.Values)
{
if (tracked.Record.IsSpatiallyProjected)
if (tracked.Record.IsSpatiallyProjected
&& tracked.Record.ProjectionKind is
LiveEntityProjectionKind.Attached)
_activeScratch.Add(tracked);
}
@ -137,6 +162,7 @@ internal sealed class LiveRenderProjectionJournal : ILiveRenderProjectionSink
public void ResetTracking()
{
_byLocalId.Clear();
_activeRootScratch.Clear();
_activeScratch.Clear();
}