feat(rendering): journal static scene projections

Append exact static and EnvCell-shell projection deltas only at committed spatial activation and detach receipts. Same-landblock rehydrate now reconciles retained, new, and omitted presentation identities without constructing or drawing the shadow scene in production.

Co-authored-by: Erik Nilsson <erikn@users.noreply.github.com>
This commit is contained in:
Erik 2026-07-24 21:57:33 +02:00
parent dbd8318417
commit 5d19c56d15
10 changed files with 997 additions and 10 deletions

View file

@ -273,6 +273,7 @@ public sealed class LandblockRetirementCoordinator
LandblockRetirementOperationResult>? _advancePresentationStep;
private readonly Func<LandblockRetirementKind, LandblockRetirementStage>
_requiredPresentationStages;
private readonly Action<GpuLandblockRetirement>? _onDetached;
private readonly Dictionary<uint, List<LandblockRetirementTicket>> _pending = new();
private readonly Queue<LandblockRetirementTicket> _pendingOrder = new();
private readonly List<uint> _completedIds = new();
@ -290,6 +291,7 @@ public sealed class LandblockRetirementCoordinator
_state = state;
_advancePresentation = advancePresentation;
_advancePresentationStep = null;
_onDetached = null;
_requiredPresentationStages = requiredPresentationStages
?? (kind => kind == LandblockRetirementKind.Full
? ProductionPresentationStages
@ -302,7 +304,8 @@ public sealed class LandblockRetirementCoordinator
advancePresentationStep,
Action<LandblockRetirementTicket> advancePresentation,
Func<LandblockRetirementKind, LandblockRetirementStage>
requiredPresentationStages)
requiredPresentationStages,
Action<GpuLandblockRetirement>? onDetached)
{
_state = state ?? throw new ArgumentNullException(nameof(state));
_advancePresentationStep = advancePresentationStep
@ -311,6 +314,7 @@ public sealed class LandblockRetirementCoordinator
?? throw new ArgumentNullException(nameof(advancePresentation));
_requiredPresentationStages = requiredPresentationStages
?? throw new ArgumentNullException(nameof(requiredPresentationStages));
_onDetached = onDetached;
}
public int PendingCount { get; private set; }
@ -335,7 +339,8 @@ public sealed class LandblockRetirementCoordinator
GpuWorldState state,
Func<LandblockRetirementTicket, LandblockRetirementOperationResult>
advancePresentationStep,
Action<LandblockRetirementTicket> advancePresentation)
Action<LandblockRetirementTicket> advancePresentation,
Action<GpuLandblockRetirement>? onDetached = null)
{
return new LandblockRetirementCoordinator(
state,
@ -343,7 +348,8 @@ public sealed class LandblockRetirementCoordinator
advancePresentation,
kind => kind == LandblockRetirementKind.Full
? ProductionPresentationStages
: ProductionPresentationStages & ~LandblockRetirementStage.Terrain);
: ProductionPresentationStages & ~LandblockRetirementStage.Terrain,
onDetached);
}
/// <summary>
@ -531,6 +537,8 @@ public sealed class LandblockRetirementCoordinator
if (_advancePresentationStep is not null)
_pendingOrder.Enqueue(ticket);
_onDetached?.Invoke(stateRetirement);
if (_advancePresentationStep is null)
{
AdvanceTicket(ticket);