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:
parent
dbd8318417
commit
5d19c56d15
10 changed files with 997 additions and 10 deletions
88
src/AcDream.App/Rendering/Scene/RenderProjectionJournal.cs
Normal file
88
src/AcDream.App/Rendering/Scene/RenderProjectionJournal.cs
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
namespace AcDream.App.Rendering.Scene;
|
||||
|
||||
/// <summary>
|
||||
/// Update-thread-owned structural journal between accepted world mutation and
|
||||
/// the disposable render projection. Structural edges are never coalesced.
|
||||
/// A successful frame publication drains the complete retained buffer.
|
||||
/// </summary>
|
||||
internal sealed class RenderProjectionJournal
|
||||
{
|
||||
private readonly List<RenderProjectionDelta> _deltas = [];
|
||||
private ulong _nextSequence = 1;
|
||||
|
||||
public RenderProjectionJournal(RenderSceneGeneration generation)
|
||||
{
|
||||
Generation = generation;
|
||||
}
|
||||
|
||||
public RenderSceneGeneration Generation { get; private set; }
|
||||
public int Count => _deltas.Count;
|
||||
public int Capacity => _deltas.Capacity;
|
||||
|
||||
public void Register(in RenderProjectionRecord record) =>
|
||||
_deltas.Add(RenderProjectionDelta.Register(
|
||||
Generation,
|
||||
NextSequence(),
|
||||
in record));
|
||||
|
||||
public void Update(
|
||||
RenderProjectionDeltaKind kind,
|
||||
in RenderProjectionRecord record) =>
|
||||
_deltas.Add(RenderProjectionDelta.Update(
|
||||
kind,
|
||||
Generation,
|
||||
NextSequence(),
|
||||
in record));
|
||||
|
||||
public void Unregister(
|
||||
RenderProjectionId id,
|
||||
RenderOwnerIncarnation incarnation) =>
|
||||
_deltas.Add(RenderProjectionDelta.Unregister(
|
||||
Generation,
|
||||
NextSequence(),
|
||||
id,
|
||||
incarnation));
|
||||
|
||||
public RenderDeltaApplyResult DrainTo(IRenderScene scene)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(scene);
|
||||
if (scene.Generation != Generation)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Journal {Generation} cannot drain into scene {scene.Generation}.");
|
||||
}
|
||||
|
||||
RenderDeltaApplyResult result =
|
||||
scene.Apply(System.Runtime.InteropServices.CollectionsMarshal.AsSpan(_deltas));
|
||||
_deltas.Clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Clear(RenderSceneGeneration replacementGeneration)
|
||||
{
|
||||
if (replacementGeneration.CompareTo(Generation) <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(replacementGeneration),
|
||||
replacementGeneration,
|
||||
"A replacement journal generation must advance.");
|
||||
}
|
||||
|
||||
_deltas.Clear();
|
||||
Generation = replacementGeneration;
|
||||
}
|
||||
|
||||
internal ReadOnlySpan<RenderProjectionDelta> Pending =>
|
||||
System.Runtime.InteropServices.CollectionsMarshal.AsSpan(_deltas);
|
||||
|
||||
private ulong NextSequence()
|
||||
{
|
||||
if (_nextSequence == ulong.MaxValue)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Render projection journal sequence exhausted.");
|
||||
}
|
||||
|
||||
return _nextSequence++;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue